Merge branch 'master' of github.com:MongoEngine/mongoengine into mongodb_40

This commit is contained in:
Bastien Gérard 2020-01-12 21:16:48 +01:00
commit ea88806630
76 changed files with 5215 additions and 4899 deletions

View File

@ -3,7 +3,7 @@
# with a very large number of jobs, hence we only test a subset of all the
# combinations:
# * MongoDB v3.4 & the latest PyMongo v3.x is currently the "main" setup,
# tested against Python v2.7, v3.5, v3.6, v3.7, PyPy and PyPy3.
# tested against Python v2.7, v3.5, v3.6, v3.7, v3.8, PyPy and PyPy3.
# * Besides that, we test the lowest actively supported Python/MongoDB/PyMongo
# combination: MongoDB v3.4, PyMongo v3.4, Python v2.7.
# * MongoDB v3.6 is tested against Python v3.6, and PyMongo v3.6, v3.7, v3.8.
@ -23,6 +23,7 @@ python:
- 3.5
- 3.6
- 3.7
- 3.8
- pypy
- pypy3
@ -33,11 +34,12 @@ env:
- MONGODB_4_0=4.0.12
- MONGODB_3_4=3.4.17
- MONGODB_3_6=3.6.12
- PYMONGO_3_10=3.10
- PYMONGO_3_9=3.9
- PYMONGO_3_6=3.6
- PYMONGO_3_4=3.4
matrix:
- MONGODB=${MONGODB_3_4} PYMONGO=${PYMONGO_3_9}
- MONGODB=${MONGODB_3_4} PYMONGO=${PYMONGO_3_10}
matrix:
# Finish the build as soon as one job fails
@ -49,7 +51,11 @@ matrix:
- python: 3.7
env: MONGODB=${MONGODB_3_6} PYMONGO=${PYMONGO_3_6}
- python: 3.7
env: MONGODB=${MONGODB_4_0} PYMONGO=${PYMONGO_3_9}
env: MONGODB=${MONGODB_3_6} PYMONGO=${PYMONGO_3_9}
- python: 3.7
env: MONGODB=${MONGODB_3_6} PYMONGO=${PYMONGO_3_10}
- python: 3.8
env: MONGODB=${MONGODB_4_0} PYMONGO=${PYMONGO_3_10}
install:
# Install Mongo
@ -62,8 +68,8 @@ install:
- pip install flake8 flake8-import-order
- pip install tox # tox 3.11.0 has requirement virtualenv>=14.0.0
- pip install virtualenv # virtualenv>=14.0.0 has dropped Python 3.2 support (and pypy3 is based on py32)
# Install the tox venv.
- tox -e $(echo py$TRAVIS_PYTHON_VERSION-mg$PYMONGO | tr -d . | sed -e 's/pypypy/pypy/') -- -e test
# tox dryrun to setup the tox venv (we run a mock test).
- tox -e $(echo py$TRAVIS_PYTHON_VERSION-mg$PYMONGO | tr -d . | sed -e 's/pypypy/pypy/') -- -a "-k=test_ci_placeholder"
# Install black for Python v3.7 only.
- if [[ $TRAVIS_PYTHON_VERSION == '3.7' ]]; then pip install black; fi
@ -75,13 +81,13 @@ before_script:
- mongo --eval 'db.version();' # Make sure mongo is awake
script:
- tox -e $(echo py$TRAVIS_PYTHON_VERSION-mg$PYMONGO | tr -d . | sed -e 's/pypypy/pypy/') -- --with-coverage
- tox -e $(echo py$TRAVIS_PYTHON_VERSION-mg$PYMONGO | tr -d . | sed -e 's/pypypy/pypy/') -- -a "--cov=mongoengine"
# For now only submit coveralls for Python v2.7. Python v3.x currently shows
# 0% coverage. That's caused by 'use_2to3', which builds the py3-compatible
# code in a separate dir and runs tests on that.
after_success:
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coveralls --verbose; fi
- if [[ $TRAVIS_PYTHON_VERSION == '2.7' ]]; then coveralls --verbose; else echo "coveralls only sent for py27"; fi
notifications:
irc: irc.freenode.org#mongoengine
@ -109,5 +115,5 @@ deploy:
on:
tags: true
repo: MongoEngine/mongoengine
condition: ($PYMONGO = ${PYMONGO_3_6}) && ($MONGODB = ${MONGODB_3_4})
condition: ($PYMONGO = ${PYMONGO_3_10}) && ($MONGODB = ${MONGODB_3_4})
python: 2.7

View File

@ -252,3 +252,6 @@ that much better:
* Paulo Amaral (https://github.com/pauloAmaral)
* Gaurav Dadhania (https://github.com/GVRV)
* Yurii Andrieiev (https://github.com/yandrieiev)
* Filip Kucharczyk (https://github.com/Pacu2)
* Eric Timmons (https://github.com/daewok)
* Matthew Simpson (https://github.com/mcsimps2)

View File

@ -54,7 +54,7 @@ General Guidelines
should adapt to the breaking change in docs/upgrade.rst.
- Write inline documentation for new classes and methods.
- Write tests and make sure they pass (make sure you have a mongod
running on the default port, then execute ``python setup.py nosetests``
running on the default port, then execute ``python setup.py test``
from the cmd line to run the test suite).
- Ensure tests pass on all supported Python, PyMongo, and MongoDB versions.
You can test various Python and PyMongo versions locally by executing

View File

@ -91,12 +91,11 @@ Some simple examples of what MongoEngine code looks like:
# Iterate over all posts using the BlogPost superclass
>>> for post in BlogPost.objects:
... print '===', post.title, '==='
... print('===', post.title, '===')
... if isinstance(post, TextPost):
... print post.content
... print(post.content)
... elif isinstance(post, LinkPost):
... print 'Link:', post.url
... print
... print('Link:', post.url)
...
# Count all blog posts and its subtypes
@ -116,7 +115,8 @@ Some simple examples of what MongoEngine code looks like:
Tests
=====
To run the test suite, ensure you are running a local instance of MongoDB on
the standard port and have ``nose`` installed. Then, run ``python setup.py nosetests``.
the standard port and have ``pytest`` installed. Then, run ``python setup.py test``
or simply ``pytest``.
To run the test suite on every supported Python and PyMongo version, you can
use ``tox``. You'll need to make sure you have each supported Python version
@ -129,16 +129,14 @@ installed in your environment and then:
# Run the test suites
$ tox
If you wish to run a subset of tests, use the nosetests convention:
If you wish to run a subset of tests, use the pytest convention:
.. code-block:: shell
# Run all the tests in a particular test file
$ python setup.py nosetests --tests tests/fields/fields.py
$ pytest tests/fields/test_fields.py
# Run only particular test class in that file
$ python setup.py nosetests --tests tests/fields/fields.py:FieldTest
# Use the -s option if you want to print some debug statements or use pdb
$ python setup.py nosetests --tests tests/fields/fields.py:FieldTest -s
$ pytest tests/fields/test_fields.py::TestField
Community
=========

View File

@ -6,6 +6,15 @@ Changelog
Development
===========
- (Fill this out as you fix issues and develop your features).
Changes in 0.19.1
=================
- Requires Pillow < 7.0.0 as it dropped Python2 support
- DEPRECATION: The interface of ``QuerySet.aggregate`` method was changed, it no longer takes an unpacked list of
pipeline steps (*pipeline) but simply takes the pipeline list just like ``pymongo.Collection.aggregate`` does. #2079
Changes in 0.19.0
=================
- BREAKING CHANGE: ``class_check`` and ``read_preference`` keyword arguments are no longer available when filtering a ``QuerySet``. #2112
- Instead of ``Doc.objects(foo=bar, read_preference=...)`` use ``Doc.objects(foo=bar).read_preference(...)``.
- Instead of ``Doc.objects(foo=bar, class_check=False)`` use ``Doc.objects(foo=bar).clear_cls_query(...)``.
@ -15,10 +24,23 @@ Development
- If you catch/use ``MongoEngineConnectionError`` in your code, you'll have to rename it.
- BREAKING CHANGE: Positional arguments when instantiating a document are no longer supported. #2103
- From now on keyword arguments (e.g. ``Doc(field_name=value)``) are required.
- BREAKING CHANGE: A ``LazyReferenceField`` is now stored in the ``_data`` field of its parent as a ``DBRef``, ``Document``, or ``EmbeddedDocument`` (``ObjectId`` is no longer allowed). #2182
- DEPRECATION: ``Q.empty`` & ``QNode.empty`` are marked as deprecated and will be removed in a next version of MongoEngine. #2210
- Added ability to check if Q or QNode are empty by parsing them to bool.
- Instead of ``Q(name="John").empty`` use ``not Q(name="John")``.
- Fix updating/modifying/deleting/reloading a document that's sharded by a field with ``db_field`` specified. #2125
- Only set no_cursor_timeout when requested (fixes an incompatibility with MongoDB 4.2) #2148
- ``ListField`` now accepts an optional ``max_length`` parameter. #2110
- Improve error message related to InvalidDocumentError #2180
- Added BulkWriteError to replace NotUniqueError which was misleading in bulk write insert #2152
- Added ability to compare Q and Q operations #2204
- Added ability to use a db alias on query_counter #2194
- Added ability to specify collations for querysets with ``Doc.objects.collation`` #2024
- Fix updates of a list field by negative index #2094
- Switch from nosetest to pytest as test runner #2114
- The codebase is now formatted using ``black``. #2109
- In bulk write insert, the detailed error message would raise in exception.
- Documentation improvements:
- Documented how `pymongo.monitoring` can be used to log all queries issued by MongoEngine to the driver.
Changes in 0.18.2
=================

View File

@ -11,7 +11,8 @@
# All configuration values have a default; values that are commented out
# serve to show the default.
import sys, os
import os
import sys
import sphinx_rtd_theme

13
docs/faq.rst Normal file
View File

@ -0,0 +1,13 @@
==========================
Frequently Asked Questions
==========================
Does MongoEngine support asynchronous drivers (Motor, TxMongo)?
---------------------------------------------------------------
No, MongoEngine is exclusively based on PyMongo and isn't designed to support other driver.
If this is a requirement for your project, check the alternative: `uMongo`_ and `MotorEngine`_.
.. _uMongo: https://umongo.readthedocs.io/
.. _MotorEngine: https://motorengine.readthedocs.io/

View File

@ -352,7 +352,7 @@ Its value can take any of the following constants:
Deletion is denied if there still exist references to the object being
deleted.
:const:`mongoengine.NULLIFY`
Any object's fields still referring to the object being deleted are removed
Any object's fields still referring to the object being deleted are set to None
(using MongoDB's "unset" operation), effectively nullifying the relationship.
:const:`mongoengine.CASCADE`
Any object containing fields that are referring to the object being deleted
@ -744,7 +744,7 @@ Document inheritance
To create a specialised type of a :class:`~mongoengine.Document` you have
defined, you may subclass it and add any extra fields or methods you may need.
As this is new class is not a direct subclass of
As this new class is not a direct subclass of
:class:`~mongoengine.Document`, it will not be stored in its own collection; it
will use the same collection as its superclass uses. This allows for more
convenient and efficient retrieval of related documents -- all you need do is
@ -767,6 +767,27 @@ document.::
Setting :attr:`allow_inheritance` to True should also be used in
:class:`~mongoengine.EmbeddedDocument` class in case you need to subclass it
When it comes to querying using :attr:`.objects()`, querying `Page.objects()` will query
both `Page` and `DatedPage` whereas querying `DatedPage` will only query the `DatedPage` documents.
Behind the scenes, MongoEngine deals with inheritance by adding a :attr:`_cls` attribute that contains
the class name in every documents. When a document is loaded, MongoEngine checks
it's :attr:`_cls` attribute and use that class to construct the instance.::
Page(title='a funky title').save()
DatedPage(title='another title', date=datetime.utcnow()).save()
print(Page.objects().count()) # 2
print(DatedPage.objects().count()) # 1
# print documents in their native form
# we remove 'id' to avoid polluting the output with unnecessary detail
qs = Page.objects.exclude('id').as_pymongo()
print(list(qs))
# [
# {'_cls': u 'Page', 'title': 'a funky title'},
# {'_cls': u 'Page.DatedPage', 'title': u 'another title', 'date': datetime.datetime(2019, 12, 13, 20, 16, 59, 993000)}
# ]
Working with existing data
--------------------------
As MongoEngine no longer defaults to needing :attr:`_cls`, you can quickly and

View File

@ -10,8 +10,9 @@ Writing
GridFS support comes in the form of the :class:`~mongoengine.fields.FileField` field
object. This field acts as a file-like object and provides a couple of
different ways of inserting and retrieving data. Arbitrary metadata such as
content type can also be stored alongside the files. In the following example,
a document is created to store details about animals, including a photo::
content type can also be stored alongside the files. The object returned when accessing a
FileField is a proxy to `Pymongo's GridFS <https://api.mongodb.com/python/current/examples/gridfs.html#gridfs-example>`_
In the following example, a document is created to store details about animals, including a photo::
class Animal(Document):
genus = StringField()
@ -20,8 +21,8 @@ a document is created to store details about animals, including a photo::
marmot = Animal(genus='Marmota', family='Sciuridae')
marmot_photo = open('marmot.jpg', 'rb')
marmot.photo.put(marmot_photo, content_type = 'image/jpeg')
with open('marmot.jpg', 'rb') as fd:
marmot.photo.put(fd, content_type = 'image/jpeg')
marmot.save()
Retrieval
@ -34,6 +35,20 @@ field. The file can also be retrieved just as easily::
photo = marmot.photo.read()
content_type = marmot.photo.content_type
.. note:: If you need to read() the content of a file multiple times, you'll need to "rewind"
the file-like object using `seek`::
marmot = Animal.objects(genus='Marmota').first()
content1 = marmot.photo.read()
assert content1 != ""
content2 = marmot.photo.read() # will be empty
assert content2 == ""
marmot.photo.seek(0) # rewind the file by setting the current position of the cursor in the file to 0
content3 = marmot.photo.read()
assert content3 == content1
Streaming
---------

View File

@ -13,4 +13,5 @@ User Guide
gridfs
signals
text-indexes
logging-monitoring
mongomock

View File

@ -0,0 +1,80 @@
==================
Logging/Monitoring
==================
It is possible to use `pymongo.monitoring <https://api.mongodb.com/python/current/api/pymongo/monitoring.html>`_ to monitor
the driver events (e.g: queries, connections, etc). This can be handy if you want to monitor the queries issued by
MongoEngine to the driver.
To use `pymongo.monitoring` with MongoEngine, you need to make sure that you are registering the listeners
**before** establishing the database connection (i.e calling `connect`):
The following snippet provides a basic logging of all command events:
.. code-block:: python
import logging
from pymongo import monitoring
from mongoengine import *
log = logging.getLogger()
log.setLevel(logging.DEBUG)
logging.basicConfig(level=logging.DEBUG)
class CommandLogger(monitoring.CommandListener):
def started(self, event):
log.debug("Command {0.command_name} with request id "
"{0.request_id} started on server "
"{0.connection_id}".format(event))
def succeeded(self, event):
log.debug("Command {0.command_name} with request id "
"{0.request_id} on server {0.connection_id} "
"succeeded in {0.duration_micros} "
"microseconds".format(event))
def failed(self, event):
log.debug("Command {0.command_name} with request id "
"{0.request_id} on server {0.connection_id} "
"failed in {0.duration_micros} "
"microseconds".format(event))
monitoring.register(CommandLogger())
class Jedi(Document):
name = StringField()
connect()
log.info('GO!')
log.info('Saving an item through MongoEngine...')
Jedi(name='Obi-Wan Kenobii').save()
log.info('Querying through MongoEngine...')
obiwan = Jedi.objects.first()
log.info('Updating through MongoEngine...')
obiwan.name = 'Obi-Wan Kenobi'
obiwan.save()
Executing this prints the following output::
INFO:root:GO!
INFO:root:Saving an item through MongoEngine...
DEBUG:root:Command insert with request id 1681692777 started on server ('localhost', 27017)
DEBUG:root:Command insert with request id 1681692777 on server ('localhost', 27017) succeeded in 562 microseconds
INFO:root:Querying through MongoEngine...
DEBUG:root:Command find with request id 1714636915 started on server ('localhost', 27017)
DEBUG:root:Command find with request id 1714636915 on server ('localhost', 27017) succeeded in 341 microseconds
INFO:root:Updating through MongoEngine...
DEBUG:root:Command update with request id 1957747793 started on server ('localhost', 27017)
DEBUG:root:Command update with request id 1957747793 on server ('localhost', 27017) succeeded in 455 microseconds
More details can of course be obtained by checking the `event` argument from the `CommandListener`.

View File

@ -2,10 +2,10 @@
Use mongomock for testing
==============================
`mongomock <https://github.com/vmalloc/mongomock/>`_ is a package to do just
`mongomock <https://github.com/vmalloc/mongomock/>`_ is a package to do just
what the name implies, mocking a mongo database.
To use with mongoengine, simply specify mongomock when connecting with
To use with mongoengine, simply specify mongomock when connecting with
mongoengine:
.. code-block:: python
@ -21,7 +21,7 @@ or with an alias:
conn = get_connection('testdb')
Example of test file:
--------
---------------------
.. code-block:: python
import unittest
@ -45,4 +45,4 @@ Example of test file:
pers.save()
fresh_pers = Person.objects().first()
self.assertEqual(fresh_pers.name, 'John')
assert fresh_pers.name == 'John'

View File

@ -222,6 +222,18 @@ keyword argument::
.. versionadded:: 0.4
Sorting/Ordering results
========================
It is possible to order the results by 1 or more keys using :meth:`~mongoengine.queryset.QuerySet.order_by`.
The order may be specified by prepending each of the keys by "+" or "-". Ascending order is assumed if there's no prefix.::
# Order by ascending date
blogs = BlogPost.objects().order_by('date') # equivalent to .order_by('+date')
# Order by ascending date first, then descending title
blogs = BlogPost.objects().order_by('+date', '-title')
Limiting and skipping results
=============================
Just as with traditional ORMs, you may limit the number of results returned or
@ -388,7 +400,7 @@ would be generating "tag-clouds"::
MongoDB aggregation API
-----------------------
If you need to run aggregation pipelines, MongoEngine provides an entry point `Pymongo's aggregation framework <https://api.mongodb.com/python/current/examples/aggregation.html#aggregation-framework>`_
If you need to run aggregation pipelines, MongoEngine provides an entry point to `Pymongo's aggregation framework <https://api.mongodb.com/python/current/examples/aggregation.html#aggregation-framework>`_
through :meth:`~mongoengine.queryset.QuerySet.aggregate`. Check out Pymongo's documentation for the syntax and pipeline.
An example of its use would be::
@ -402,7 +414,7 @@ An example of its use would be::
{"$sort" : {"name" : -1}},
{"$project": {"_id": 0, "name": {"$toUpper": "$name"}}}
]
data = Person.objects().aggregate(*pipeline)
data = Person.objects().aggregate(pipeline)
assert data == [{'name': 'BOB'}, {'name': 'JOHN'}]
Query efficiency and performance
@ -585,7 +597,8 @@ cannot use the `$` syntax in keyword arguments it has been mapped to `S`::
['database', 'mongodb']
From MongoDB version 2.6, push operator supports $position value which allows
to push values with index.
to push values with index::
>>> post = BlogPost(title="Test", tags=["mongo"])
>>> post.save()
>>> post.update(push__tags__0=["database", "code"])

View File

@ -23,9 +23,18 @@ MongoDB. To install it, simply run
:doc:`upgrade`
How to upgrade MongoEngine.
:doc:`faq`
Frequently Asked Questions
:doc:`django`
Using MongoEngine and Django
MongoDB and driver support
--------------------------
MongoEngine is based on the PyMongo driver and tested against multiple versions of MongoDB.
For further details, please refer to the `readme <https://github.com/MongoEngine/mongoengine#mongoengine>`_.
Community
---------
@ -73,6 +82,7 @@ formats for offline reading.
apireference
changelog
upgrade
faq
django
Indices and tables

View File

@ -52,7 +52,7 @@ rename its occurrences.
This release includes a major rehaul of MongoEngine's code quality and
introduces a few breaking changes. It also touches many different parts of
the package and although all the changes have been tested and scrutinized,
you're encouraged to thorougly test the upgrade.
you're encouraged to thoroughly test the upgrade.
First breaking change involves renaming `ConnectionError` to `MongoEngineConnectionError`.
If you import or catch this exception, you'll need to rename it in your code.

View File

@ -28,7 +28,7 @@ __all__ = (
)
VERSION = (0, 18, 2)
VERSION = (0, 19, 1)
def get_version():

View File

@ -120,6 +120,9 @@ class BaseList(list):
super(BaseList, self).__init__(list_items)
def __getitem__(self, key):
# change index to positive value because MongoDB does not support negative one
if isinstance(key, int) and key < 0:
key = len(self) + key
value = super(BaseList, self).__getitem__(key)
if isinstance(key, slice):

View File

@ -62,13 +62,13 @@ class BaseDocument(object):
"""
Initialise a document or an embedded document.
:param dict values: A dictionary of keys and values for the document.
:param values: A dictionary of keys and values for the document.
It may contain additional reserved keywords, e.g. "__auto_convert".
:param bool __auto_convert: If True, supplied values will be converted
:param __auto_convert: If True, supplied values will be converted
to Python-type values via each field's `to_python` method.
:param set __only_fields: A set of fields that have been loaded for
:param __only_fields: A set of fields that have been loaded for
this document. Empty if all fields have been loaded.
:param bool _created: Indicates whether this is a brand new document
:param _created: Indicates whether this is a brand new document
or whether it's already been persisted before. Defaults to true.
"""
self._initialised = False
@ -732,7 +732,10 @@ class BaseDocument(object):
only_fields = []
if son and not isinstance(son, dict):
raise ValueError("The source SON object needs to be of type 'dict'")
raise ValueError(
"The source SON object needs to be of type 'dict' but a '%s' was found"
% type(son)
)
# Get the class name from the document, falling back to the given
# class if unavailable
@ -770,7 +773,9 @@ class BaseDocument(object):
errors_dict[field_name] = e
if errors_dict:
errors = "\n".join(["%s - %s" % (k, v) for k, v in errors_dict.items()])
errors = "\n".join(
["Field '%s' - %s" % (k, v) for k, v in errors_dict.items()]
)
msg = "Invalid data to create a `%s` instance.\n%s" % (
cls._class_name,
errors,

View File

@ -171,7 +171,7 @@ class no_sub_classes(object):
class query_counter(object):
"""Query_counter context manager to get the number of queries.
This works by updating the `profiling_level` of the database so that all queries get logged,
resetting the db.system.profile collection at the beginnig of the context and counting the new entries.
resetting the db.system.profile collection at the beginning of the context and counting the new entries.
This was designed for debugging purpose. In fact it is a global counter so queries issued by other threads/processes
can interfere with it
@ -182,10 +182,10 @@ class query_counter(object):
- Some queries are ignored by default by the counter (killcursors, db.system.indexes)
"""
def __init__(self):
def __init__(self, alias=DEFAULT_CONNECTION_NAME):
"""Construct the query_counter
"""
self.db = get_db()
self.db = get_db(alias=alias)
self.initial_profiling_level = None
self._ctx_query_counter = 0 # number of queries issued by the context
@ -247,8 +247,8 @@ class query_counter(object):
- self._ctx_query_counter
)
self._ctx_query_counter += (
1
) # Account for the query we just issued to gather the information
1 # Account for the query we just issued to gather the information
)
return count

View File

@ -41,6 +41,7 @@ from mongoengine.common import _import_class
from mongoengine.connection import DEFAULT_CONNECTION_NAME, get_db
from mongoengine.document import Document, EmbeddedDocument
from mongoengine.errors import DoesNotExist, InvalidQueryError, ValidationError
from mongoengine.mongodb_support import MONGODB_36, get_mongodb_version
from mongoengine.python_support import StringIO
from mongoengine.queryset import DO_NOTHING
from mongoengine.queryset.base import BaseQuerySet
@ -1051,6 +1052,15 @@ def key_has_dot_or_dollar(d):
return True
def key_starts_with_dollar(d):
"""Helper function to recursively determine if any key in a
dictionary starts with a dollar
"""
for k, v in d.items():
if (k.startswith("$")) or (isinstance(v, dict) and key_starts_with_dollar(v)):
return True
class DictField(ComplexBaseField):
"""A dictionary field that wraps a standard Python dictionary. This is
similar to an embedded document, but the structure is not defined.
@ -1077,11 +1087,18 @@ class DictField(ComplexBaseField):
if key_not_string(value):
msg = "Invalid dictionary key - documents must have only string keys"
self.error(msg)
if key_has_dot_or_dollar(value):
curr_mongo_ver = get_mongodb_version()
if curr_mongo_ver < MONGODB_36 and key_has_dot_or_dollar(value):
self.error(
'Invalid dictionary key name - keys may not contain "."'
' or startswith "$" characters'
)
elif curr_mongo_ver >= MONGODB_36 and key_starts_with_dollar(value):
self.error(
'Invalid dictionary key name - keys may not startswith "$" characters'
)
super(DictField, self).validate(value)
def lookup_member(self, member_name):
@ -2502,6 +2519,13 @@ class LazyReferenceField(BaseField):
else:
return pk
def to_python(self, value):
"""Convert a MongoDB-compatible type to a Python type."""
if not isinstance(value, (DBRef, Document, EmbeddedDocument)):
collection = self.document_type._get_collection_name()
value = DBRef(collection, self.document_type.id.to_python(value))
return value
def validate(self, value):
if isinstance(value, LazyReference):
if value.collection != self.document_type._get_collection_name():

View File

@ -302,7 +302,7 @@ class BaseQuerySet(object):
``insert(..., {w: 2, fsync: True})`` will wait until at least
two servers have recorded the write and will force an fsync on
each server being written to.
:parm signal_kwargs: (optional) kwargs dictionary to be passed to
:param signal_kwargs: (optional) kwargs dictionary to be passed to
the signal calls.
By default returns document instances, set ``load_bulk`` to False to
@ -1193,9 +1193,7 @@ class BaseQuerySet(object):
validate_read_preference("read_preference", read_preference)
queryset = self.clone()
queryset._read_preference = read_preference
queryset._cursor_obj = (
None
) # we need to re-create the cursor object whenever we apply read_preference
queryset._cursor_obj = None # we need to re-create the cursor object whenever we apply read_preference
return queryset
def scalar(self, *fields):
@ -1257,16 +1255,27 @@ class BaseQuerySet(object):
for data in son_data
]
def aggregate(self, *pipeline, **kwargs):
"""
Perform a aggregate function based in your queryset params
def aggregate(self, pipeline, *suppl_pipeline, **kwargs):
"""Perform a aggregate function based in your queryset params
:param pipeline: list of aggregation commands,\
see: http://docs.mongodb.org/manual/core/aggregation-pipeline/
:param suppl_pipeline: unpacked list of pipeline (added to support deprecation of the old interface)
parameter will be removed shortly
:param kwargs: (optional) kwargs dictionary to be passed to pymongo's aggregate call
See https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.aggregate
.. versionadded:: 0.9
"""
initial_pipeline = []
using_deprecated_interface = isinstance(pipeline, dict) or bool(suppl_pipeline)
user_pipeline = [pipeline] if isinstance(pipeline, dict) else list(pipeline)
if using_deprecated_interface:
msg = "Calling .aggregate() with un unpacked list (*pipeline) is deprecated, it will soon change and will expect a list (similar to pymongo.Collection.aggregate interface), see documentation"
warnings.warn(msg, DeprecationWarning)
user_pipeline += suppl_pipeline
initial_pipeline = []
if self._query:
initial_pipeline.append({"$match": self._query})
@ -1283,14 +1292,14 @@ class BaseQuerySet(object):
if self._skip is not None:
initial_pipeline.append({"$skip": self._skip})
pipeline = initial_pipeline + list(pipeline)
final_pipeline = initial_pipeline + user_pipeline
collection = self._collection
if self._read_preference is not None:
return self._collection.with_options(
collection = self._collection.with_options(
read_preference=self._read_preference
).aggregate(pipeline, cursor={}, **kwargs)
return self._collection.aggregate(pipeline, cursor={}, **kwargs)
)
return collection.aggregate(final_pipeline, cursor={}, **kwargs)
# JS functionality
def map_reduce(
@ -1639,6 +1648,7 @@ class BaseQuerySet(object):
).find(self._query, **self._cursor_args)
else:
self._cursor_obj = self._collection.find(self._query, **self._cursor_args)
# Apply "where" clauses to cursor
if self._where_clause:
where_clause = self._sub_js_fields(self._where_clause)

View File

@ -1,4 +1,5 @@
import copy
import warnings
from mongoengine.errors import InvalidQueryError
from mongoengine.queryset import transform
@ -96,9 +97,11 @@ class QNode(object):
"""Combine this node with another node into a QCombination
object.
"""
# If the other Q() is empty, ignore it and just use `self`.
if getattr(other, "empty", True):
return self
# Or if this Q is empty, ignore it and just use `other`.
if self.empty:
return other
@ -106,6 +109,8 @@ class QNode(object):
@property
def empty(self):
msg = "'empty' property is deprecated in favour of using 'not bool(filter)'"
warnings.warn(msg, DeprecationWarning)
return False
def __or__(self, other):
@ -135,6 +140,11 @@ class QCombination(QNode):
op = " & " if self.operation is self.AND else " | "
return "(%s)" % op.join([repr(node) for node in self.children])
def __bool__(self):
return bool(self.children)
__nonzero__ = __bool__ # For Py2 support
def accept(self, visitor):
for i in range(len(self.children)):
if isinstance(self.children[i], QNode):
@ -144,8 +154,17 @@ class QCombination(QNode):
@property
def empty(self):
msg = "'empty' property is deprecated in favour of using 'not bool(filter)'"
warnings.warn(msg, DeprecationWarning)
return not bool(self.children)
def __eq__(self, other):
return (
self.__class__ == other.__class__
and self.operation == other.operation
and self.children == other.children
)
class Q(QNode):
"""A simple query object, used in a query tree to build up more complex
@ -158,6 +177,14 @@ class Q(QNode):
def __repr__(self):
return "Q(**%s)" % repr(self.query)
def __bool__(self):
return bool(self.query)
__nonzero__ = __bool__ # For Py2 support
def __eq__(self, other):
return self.__class__ == other.__class__ and self.query == other.query
def accept(self, visitor):
return visitor.visit_query(self)

View File

@ -1,4 +1,3 @@
nose
pymongo>=3.4
six==1.10.0
Sphinx==1.5.5

View File

@ -1,11 +1,10 @@
[nosetests]
verbosity=2
detailed-errors=1
#tests=tests
cover-package=mongoengine
[flake8]
ignore=E501,F401,F403,F405,I201,I202,W504, W605, W503
exclude=build,dist,docs,venv,venv3,.tox,.eggs,tests
max-complexity=47
application-import-names=mongoengine,tests
[tool:pytest]
# Limits the discovery to tests directory
# avoids that it runs for instance the benchmark
testpaths = tests

View File

@ -1,6 +1,9 @@
import os
import sys
from pkg_resources import normalize_path
from setuptools import find_packages, setup
from setuptools.command.test import test as TestCommand
# Hack to silence atexit traceback in newer python versions
try:
@ -24,6 +27,62 @@ def get_version(version_tuple):
return ".".join(map(str, version_tuple))
class PyTest(TestCommand):
"""Will force pytest to search for tests inside the build directory
for 2to3 converted code (used by tox), instead of the current directory.
Required as long as we need 2to3
Known Limitation: https://tox.readthedocs.io/en/latest/example/pytest.html#known-issues-and-limitations
Source: https://www.hackzine.org/python-testing-with-pytest-and-2to3-plus-tox-and-travis-ci.html
"""
# https://pytest.readthedocs.io/en/2.7.3/goodpractises.html#integration-with-setuptools-test-commands
# Allows to provide pytest command argument through the test runner command `python setup.py test`
# e.g: `python setup.py test -a "-k=test"`
# This only works for 1 argument though
user_options = [("pytest-args=", "a", "Arguments to pass to py.test")]
def initialize_options(self):
TestCommand.initialize_options(self)
self.pytest_args = ""
def finalize_options(self):
TestCommand.finalize_options(self)
self.test_args = ["tests"]
self.test_suite = True
def run_tests(self):
# import here, cause outside the eggs aren't loaded
from pkg_resources import _namespace_packages
import pytest
# Purge modules under test from sys.modules. The test loader will
# re-import them from the build location. Required when 2to3 is used
# with namespace packages.
if sys.version_info >= (3,) and getattr(self.distribution, "use_2to3", False):
module = self.test_args[-1].split(".")[0]
if module in _namespace_packages:
del_modules = []
if module in sys.modules:
del_modules.append(module)
module += "."
for name in sys.modules:
if name.startswith(module):
del_modules.append(name)
map(sys.modules.__delitem__, del_modules)
# Run on the build directory for 2to3-built code
# This will prevent the old 2.x code from being found
# by py.test discovery mechanism, that apparently
# ignores sys.path..
ei_cmd = self.get_finalized_command("egg_info")
self.test_args = [normalize_path(ei_cmd.egg_base)]
cmd_args = self.test_args + ([self.pytest_args] if self.pytest_args else [])
errno = pytest.main(cmd_args)
sys.exit(errno)
# Dirty hack to get version number from monogengine/__init__.py - we can't
# import it as it depends on PyMongo and PyMongo isn't installed until this
# file is read
@ -51,11 +110,17 @@ CLASSIFIERS = [
extra_opts = {
"packages": find_packages(exclude=["tests", "tests.*"]),
"tests_require": ["nose", "coverage==4.2", "blinker", "Pillow>=2.0.0"],
"tests_require": [
"pytest<5.0",
"pytest-cov",
"coverage<5.0", # recent coverage switched to sqlite format for the .coverage file which isn't handled properly by coveralls
"blinker",
"Pillow>=2.0.0, <7.0.0", # 7.0.0 dropped Python2 support
],
}
if sys.version_info[0] == 3:
extra_opts["use_2to3"] = True
if "test" in sys.argv or "nosetests" in sys.argv:
if "test" in sys.argv:
extra_opts["packages"] = find_packages()
extra_opts["package_data"] = {
"tests": ["fields/mongoengine.png", "fields/mongodb_leaf.png"]
@ -78,7 +143,7 @@ setup(
long_description=LONG_DESCRIPTION,
platforms=["any"],
classifiers=CLASSIFIERS,
install_requires=["pymongo>=3.4", "six"],
test_suite="nose.collector",
install_requires=["pymongo>=3.4, <4.0", "six>=1.10.0"],
cmdclass={"test": PyTest},
**extra_opts
)

View File

@ -31,7 +31,5 @@ class TestAllWarnings(unittest.TestCase):
meta = {"collection": "fail"}
warning = self.warning_list[0]
self.assertEqual(SyntaxWarning, warning["category"])
self.assertEqual(
"non_abstract_base", InheritedDocumentFailTest._get_collection_name()
)
assert SyntaxWarning == warning["category"]
assert "non_abstract_base" == InheritedDocumentFailTest._get_collection_name()

View File

@ -29,43 +29,40 @@ class TestClassMethods(unittest.TestCase):
def test_definition(self):
"""Ensure that document may be defined using fields.
"""
self.assertEqual(
["_cls", "age", "id", "name"], sorted(self.Person._fields.keys())
)
self.assertEqual(
["IntField", "ObjectIdField", "StringField", "StringField"],
sorted([x.__class__.__name__ for x in self.Person._fields.values()]),
assert ["_cls", "age", "id", "name"] == sorted(self.Person._fields.keys())
assert ["IntField", "ObjectIdField", "StringField", "StringField"] == sorted(
[x.__class__.__name__ for x in self.Person._fields.values()]
)
def test_get_db(self):
"""Ensure that get_db returns the expected db.
"""
db = self.Person._get_db()
self.assertEqual(self.db, db)
assert self.db == db
def test_get_collection_name(self):
"""Ensure that get_collection_name returns the expected collection
name.
"""
collection_name = "person"
self.assertEqual(collection_name, self.Person._get_collection_name())
assert collection_name == self.Person._get_collection_name()
def test_get_collection(self):
"""Ensure that get_collection returns the expected collection.
"""
collection_name = "person"
collection = self.Person._get_collection()
self.assertEqual(self.db[collection_name], collection)
assert self.db[collection_name] == collection
def test_drop_collection(self):
"""Ensure that the collection may be dropped from the database.
"""
collection_name = "person"
self.Person(name="Test").save()
self.assertIn(collection_name, list_collection_names(self.db))
assert collection_name in list_collection_names(self.db)
self.Person.drop_collection()
self.assertNotIn(collection_name, list_collection_names(self.db))
assert collection_name not in list_collection_names(self.db)
def test_register_delete_rule(self):
"""Ensure that register delete rule adds a delete rule to the document
@ -75,12 +72,10 @@ class TestClassMethods(unittest.TestCase):
class Job(Document):
employee = ReferenceField(self.Person)
self.assertEqual(self.Person._meta.get("delete_rules"), None)
assert self.Person._meta.get("delete_rules") is None
self.Person.register_delete_rule(Job, "employee", NULLIFY)
self.assertEqual(
self.Person._meta["delete_rules"], {(Job, "employee"): NULLIFY}
)
assert self.Person._meta["delete_rules"] == {(Job, "employee"): NULLIFY}
def test_compare_indexes(self):
""" Ensure that the indexes are properly created and that
@ -98,22 +93,22 @@ class TestClassMethods(unittest.TestCase):
BlogPost.drop_collection()
BlogPost.ensure_indexes()
self.assertEqual(BlogPost.compare_indexes(), {"missing": [], "extra": []})
assert BlogPost.compare_indexes() == {"missing": [], "extra": []}
BlogPost.ensure_index(["author", "description"])
self.assertEqual(
BlogPost.compare_indexes(),
{"missing": [], "extra": [[("author", 1), ("description", 1)]]},
)
assert BlogPost.compare_indexes() == {
"missing": [],
"extra": [[("author", 1), ("description", 1)]],
}
BlogPost._get_collection().drop_index("author_1_description_1")
self.assertEqual(BlogPost.compare_indexes(), {"missing": [], "extra": []})
assert BlogPost.compare_indexes() == {"missing": [], "extra": []}
BlogPost._get_collection().drop_index("author_1_title_1")
self.assertEqual(
BlogPost.compare_indexes(),
{"missing": [[("author", 1), ("title", 1)]], "extra": []},
)
assert BlogPost.compare_indexes() == {
"missing": [[("author", 1), ("title", 1)]],
"extra": [],
}
def test_compare_indexes_inheritance(self):
""" Ensure that the indexes are properly created and that
@ -138,22 +133,22 @@ class TestClassMethods(unittest.TestCase):
BlogPost.ensure_indexes()
BlogPostWithTags.ensure_indexes()
self.assertEqual(BlogPost.compare_indexes(), {"missing": [], "extra": []})
assert BlogPost.compare_indexes() == {"missing": [], "extra": []}
BlogPostWithTags.ensure_index(["author", "tag_list"])
self.assertEqual(
BlogPost.compare_indexes(),
{"missing": [], "extra": [[("_cls", 1), ("author", 1), ("tag_list", 1)]]},
)
assert BlogPost.compare_indexes() == {
"missing": [],
"extra": [[("_cls", 1), ("author", 1), ("tag_list", 1)]],
}
BlogPostWithTags._get_collection().drop_index("_cls_1_author_1_tag_list_1")
self.assertEqual(BlogPost.compare_indexes(), {"missing": [], "extra": []})
assert BlogPost.compare_indexes() == {"missing": [], "extra": []}
BlogPostWithTags._get_collection().drop_index("_cls_1_author_1_tags_1")
self.assertEqual(
BlogPost.compare_indexes(),
{"missing": [[("_cls", 1), ("author", 1), ("tags", 1)]], "extra": []},
)
assert BlogPost.compare_indexes() == {
"missing": [[("_cls", 1), ("author", 1), ("tags", 1)]],
"extra": [],
}
def test_compare_indexes_multiple_subclasses(self):
""" Ensure that compare_indexes behaves correctly if called from a
@ -182,13 +177,9 @@ class TestClassMethods(unittest.TestCase):
BlogPostWithTags.ensure_indexes()
BlogPostWithCustomField.ensure_indexes()
self.assertEqual(BlogPost.compare_indexes(), {"missing": [], "extra": []})
self.assertEqual(
BlogPostWithTags.compare_indexes(), {"missing": [], "extra": []}
)
self.assertEqual(
BlogPostWithCustomField.compare_indexes(), {"missing": [], "extra": []}
)
assert BlogPost.compare_indexes() == {"missing": [], "extra": []}
assert BlogPostWithTags.compare_indexes() == {"missing": [], "extra": []}
assert BlogPostWithCustomField.compare_indexes() == {"missing": [], "extra": []}
def test_compare_indexes_for_text_indexes(self):
""" Ensure that compare_indexes behaves correctly for text indexes """
@ -210,7 +201,7 @@ class TestClassMethods(unittest.TestCase):
Doc.ensure_indexes()
actual = Doc.compare_indexes()
expected = {"missing": [], "extra": []}
self.assertEqual(actual, expected)
assert actual == expected
def test_list_indexes_inheritance(self):
""" ensure that all of the indexes are listed regardless of the super-
@ -240,19 +231,14 @@ class TestClassMethods(unittest.TestCase):
BlogPostWithTags.ensure_indexes()
BlogPostWithTagsAndExtraText.ensure_indexes()
self.assertEqual(BlogPost.list_indexes(), BlogPostWithTags.list_indexes())
self.assertEqual(
BlogPost.list_indexes(), BlogPostWithTagsAndExtraText.list_indexes()
)
self.assertEqual(
BlogPost.list_indexes(),
[
[("_cls", 1), ("author", 1), ("tags", 1)],
[("_cls", 1), ("author", 1), ("tags", 1), ("extra_text", 1)],
[(u"_id", 1)],
[("_cls", 1)],
],
)
assert BlogPost.list_indexes() == BlogPostWithTags.list_indexes()
assert BlogPost.list_indexes() == BlogPostWithTagsAndExtraText.list_indexes()
assert BlogPost.list_indexes() == [
[("_cls", 1), ("author", 1), ("tags", 1)],
[("_cls", 1), ("author", 1), ("tags", 1), ("extra_text", 1)],
[(u"_id", 1)],
[("_cls", 1)],
]
def test_register_delete_rule_inherited(self):
class Vaccine(Document):
@ -271,8 +257,8 @@ class TestClassMethods(unittest.TestCase):
class Cat(Animal):
name = StringField(required=True)
self.assertEqual(Vaccine._meta["delete_rules"][(Animal, "vaccine_made")], PULL)
self.assertEqual(Vaccine._meta["delete_rules"][(Cat, "vaccine_made")], PULL)
assert Vaccine._meta["delete_rules"][(Animal, "vaccine_made")] == PULL
assert Vaccine._meta["delete_rules"][(Cat, "vaccine_made")] == PULL
def test_collection_naming(self):
"""Ensure that a collection with a specified name may be used.
@ -281,19 +267,17 @@ class TestClassMethods(unittest.TestCase):
class DefaultNamingTest(Document):
pass
self.assertEqual(
"default_naming_test", DefaultNamingTest._get_collection_name()
)
assert "default_naming_test" == DefaultNamingTest._get_collection_name()
class CustomNamingTest(Document):
meta = {"collection": "pimp_my_collection"}
self.assertEqual("pimp_my_collection", CustomNamingTest._get_collection_name())
assert "pimp_my_collection" == CustomNamingTest._get_collection_name()
class DynamicNamingTest(Document):
meta = {"collection": lambda c: "DYNAMO"}
self.assertEqual("DYNAMO", DynamicNamingTest._get_collection_name())
assert "DYNAMO" == DynamicNamingTest._get_collection_name()
# Use Abstract class to handle backwards compatibility
class BaseDocument(Document):
@ -302,14 +286,12 @@ class TestClassMethods(unittest.TestCase):
class OldNamingConvention(BaseDocument):
pass
self.assertEqual(
"oldnamingconvention", OldNamingConvention._get_collection_name()
)
assert "oldnamingconvention" == OldNamingConvention._get_collection_name()
class InheritedAbstractNamingTest(BaseDocument):
meta = {"collection": "wibble"}
self.assertEqual("wibble", InheritedAbstractNamingTest._get_collection_name())
assert "wibble" == InheritedAbstractNamingTest._get_collection_name()
# Mixin tests
class BaseMixin(object):
@ -318,8 +300,9 @@ class TestClassMethods(unittest.TestCase):
class OldMixinNamingConvention(Document, BaseMixin):
pass
self.assertEqual(
"oldmixinnamingconvention", OldMixinNamingConvention._get_collection_name()
assert (
"oldmixinnamingconvention"
== OldMixinNamingConvention._get_collection_name()
)
class BaseMixin(object):
@ -331,7 +314,7 @@ class TestClassMethods(unittest.TestCase):
class MyDocument(BaseDocument):
pass
self.assertEqual("basedocument", MyDocument._get_collection_name())
assert "basedocument" == MyDocument._get_collection_name()
def test_custom_collection_name_operations(self):
"""Ensure that a collection with a specified name is used as expected.
@ -343,16 +326,16 @@ class TestClassMethods(unittest.TestCase):
meta = {"collection": collection_name}
Person(name="Test User").save()
self.assertIn(collection_name, list_collection_names(self.db))
assert collection_name in list_collection_names(self.db)
user_obj = self.db[collection_name].find_one()
self.assertEqual(user_obj["name"], "Test User")
assert user_obj["name"] == "Test User"
user_obj = Person.objects[0]
self.assertEqual(user_obj.name, "Test User")
assert user_obj.name == "Test User"
Person.drop_collection()
self.assertNotIn(collection_name, list_collection_names(self.db))
assert collection_name not in list_collection_names(self.db)
def test_collection_name_and_primary(self):
"""Ensure that a collection with a specified name may be used.
@ -365,7 +348,7 @@ class TestClassMethods(unittest.TestCase):
Person(name="Test User").save()
user_obj = Person.objects.first()
self.assertEqual(user_obj.name, "Test User")
assert user_obj.name == "Test User"
Person.drop_collection()

View File

@ -41,40 +41,40 @@ class TestDelta(MongoDBTestCase):
doc.save()
doc = Doc.objects.first()
self.assertEqual(doc._get_changed_fields(), [])
self.assertEqual(doc._delta(), ({}, {}))
assert doc._get_changed_fields() == []
assert doc._delta() == ({}, {})
doc.string_field = "hello"
self.assertEqual(doc._get_changed_fields(), ["string_field"])
self.assertEqual(doc._delta(), ({"string_field": "hello"}, {}))
assert doc._get_changed_fields() == ["string_field"]
assert doc._delta() == ({"string_field": "hello"}, {})
doc._changed_fields = []
doc.int_field = 1
self.assertEqual(doc._get_changed_fields(), ["int_field"])
self.assertEqual(doc._delta(), ({"int_field": 1}, {}))
assert doc._get_changed_fields() == ["int_field"]
assert doc._delta() == ({"int_field": 1}, {})
doc._changed_fields = []
dict_value = {"hello": "world", "ping": "pong"}
doc.dict_field = dict_value
self.assertEqual(doc._get_changed_fields(), ["dict_field"])
self.assertEqual(doc._delta(), ({"dict_field": dict_value}, {}))
assert doc._get_changed_fields() == ["dict_field"]
assert doc._delta() == ({"dict_field": dict_value}, {})
doc._changed_fields = []
list_value = ["1", 2, {"hello": "world"}]
doc.list_field = list_value
self.assertEqual(doc._get_changed_fields(), ["list_field"])
self.assertEqual(doc._delta(), ({"list_field": list_value}, {}))
assert doc._get_changed_fields() == ["list_field"]
assert doc._delta() == ({"list_field": list_value}, {})
# Test unsetting
doc._changed_fields = []
doc.dict_field = {}
self.assertEqual(doc._get_changed_fields(), ["dict_field"])
self.assertEqual(doc._delta(), ({}, {"dict_field": 1}))
assert doc._get_changed_fields() == ["dict_field"]
assert doc._delta() == ({}, {"dict_field": 1})
doc._changed_fields = []
doc.list_field = []
self.assertEqual(doc._get_changed_fields(), ["list_field"])
self.assertEqual(doc._delta(), ({}, {"list_field": 1}))
assert doc._get_changed_fields() == ["list_field"]
assert doc._delta() == ({}, {"list_field": 1})
def test_delta_recursive(self):
self.delta_recursive(Document, EmbeddedDocument)
@ -102,8 +102,8 @@ class TestDelta(MongoDBTestCase):
doc.save()
doc = Doc.objects.first()
self.assertEqual(doc._get_changed_fields(), [])
self.assertEqual(doc._delta(), ({}, {}))
assert doc._get_changed_fields() == []
assert doc._delta() == ({}, {})
embedded_1 = Embedded()
embedded_1.id = "010101"
@ -113,7 +113,7 @@ class TestDelta(MongoDBTestCase):
embedded_1.list_field = ["1", 2, {"hello": "world"}]
doc.embedded_field = embedded_1
self.assertEqual(doc._get_changed_fields(), ["embedded_field"])
assert doc._get_changed_fields() == ["embedded_field"]
embedded_delta = {
"id": "010101",
@ -122,27 +122,27 @@ class TestDelta(MongoDBTestCase):
"dict_field": {"hello": "world"},
"list_field": ["1", 2, {"hello": "world"}],
}
self.assertEqual(doc.embedded_field._delta(), (embedded_delta, {}))
self.assertEqual(doc._delta(), ({"embedded_field": embedded_delta}, {}))
assert doc.embedded_field._delta() == (embedded_delta, {})
assert doc._delta() == ({"embedded_field": embedded_delta}, {})
doc.save()
doc = doc.reload(10)
doc.embedded_field.dict_field = {}
self.assertEqual(doc._get_changed_fields(), ["embedded_field.dict_field"])
self.assertEqual(doc.embedded_field._delta(), ({}, {"dict_field": 1}))
self.assertEqual(doc._delta(), ({}, {"embedded_field.dict_field": 1}))
assert doc._get_changed_fields() == ["embedded_field.dict_field"]
assert doc.embedded_field._delta() == ({}, {"dict_field": 1})
assert doc._delta() == ({}, {"embedded_field.dict_field": 1})
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.dict_field, {})
assert doc.embedded_field.dict_field == {}
doc.embedded_field.list_field = []
self.assertEqual(doc._get_changed_fields(), ["embedded_field.list_field"])
self.assertEqual(doc.embedded_field._delta(), ({}, {"list_field": 1}))
self.assertEqual(doc._delta(), ({}, {"embedded_field.list_field": 1}))
assert doc._get_changed_fields() == ["embedded_field.list_field"]
assert doc.embedded_field._delta() == ({}, {"list_field": 1})
assert doc._delta() == ({}, {"embedded_field.list_field": 1})
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.list_field, [])
assert doc.embedded_field.list_field == []
embedded_2 = Embedded()
embedded_2.string_field = "hello"
@ -151,148 +151,128 @@ class TestDelta(MongoDBTestCase):
embedded_2.list_field = ["1", 2, {"hello": "world"}]
doc.embedded_field.list_field = ["1", 2, embedded_2]
self.assertEqual(doc._get_changed_fields(), ["embedded_field.list_field"])
assert doc._get_changed_fields() == ["embedded_field.list_field"]
self.assertEqual(
doc.embedded_field._delta(),
(
{
"list_field": [
"1",
2,
{
"_cls": "Embedded",
"string_field": "hello",
"dict_field": {"hello": "world"},
"int_field": 1,
"list_field": ["1", 2, {"hello": "world"}],
},
]
},
{},
),
assert doc.embedded_field._delta() == (
{
"list_field": [
"1",
2,
{
"_cls": "Embedded",
"string_field": "hello",
"dict_field": {"hello": "world"},
"int_field": 1,
"list_field": ["1", 2, {"hello": "world"}],
},
]
},
{},
)
self.assertEqual(
doc._delta(),
(
{
"embedded_field.list_field": [
"1",
2,
{
"_cls": "Embedded",
"string_field": "hello",
"dict_field": {"hello": "world"},
"int_field": 1,
"list_field": ["1", 2, {"hello": "world"}],
},
]
},
{},
),
assert doc._delta() == (
{
"embedded_field.list_field": [
"1",
2,
{
"_cls": "Embedded",
"string_field": "hello",
"dict_field": {"hello": "world"},
"int_field": 1,
"list_field": ["1", 2, {"hello": "world"}],
},
]
},
{},
)
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.list_field[0], "1")
self.assertEqual(doc.embedded_field.list_field[1], 2)
assert doc.embedded_field.list_field[0] == "1"
assert doc.embedded_field.list_field[1] == 2
for k in doc.embedded_field.list_field[2]._fields:
self.assertEqual(doc.embedded_field.list_field[2][k], embedded_2[k])
assert doc.embedded_field.list_field[2][k] == embedded_2[k]
doc.embedded_field.list_field[2].string_field = "world"
self.assertEqual(
doc._get_changed_fields(), ["embedded_field.list_field.2.string_field"]
assert doc._get_changed_fields() == ["embedded_field.list_field.2.string_field"]
assert doc.embedded_field._delta() == (
{"list_field.2.string_field": "world"},
{},
)
self.assertEqual(
doc.embedded_field._delta(), ({"list_field.2.string_field": "world"}, {})
)
self.assertEqual(
doc._delta(), ({"embedded_field.list_field.2.string_field": "world"}, {})
assert doc._delta() == (
{"embedded_field.list_field.2.string_field": "world"},
{},
)
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.list_field[2].string_field, "world")
assert doc.embedded_field.list_field[2].string_field == "world"
# Test multiple assignments
doc.embedded_field.list_field[2].string_field = "hello world"
doc.embedded_field.list_field[2] = doc.embedded_field.list_field[2]
self.assertEqual(doc._get_changed_fields(), ["embedded_field.list_field.2"])
self.assertEqual(
doc.embedded_field._delta(),
(
{
"list_field.2": {
"_cls": "Embedded",
"string_field": "hello world",
"int_field": 1,
"list_field": ["1", 2, {"hello": "world"}],
"dict_field": {"hello": "world"},
}
},
{},
),
assert doc._get_changed_fields() == ["embedded_field.list_field.2"]
assert doc.embedded_field._delta() == (
{
"list_field.2": {
"_cls": "Embedded",
"string_field": "hello world",
"int_field": 1,
"list_field": ["1", 2, {"hello": "world"}],
"dict_field": {"hello": "world"},
}
},
{},
)
self.assertEqual(
doc._delta(),
(
{
"embedded_field.list_field.2": {
"_cls": "Embedded",
"string_field": "hello world",
"int_field": 1,
"list_field": ["1", 2, {"hello": "world"}],
"dict_field": {"hello": "world"},
}
},
{},
),
assert doc._delta() == (
{
"embedded_field.list_field.2": {
"_cls": "Embedded",
"string_field": "hello world",
"int_field": 1,
"list_field": ["1", 2, {"hello": "world"}],
"dict_field": {"hello": "world"},
}
},
{},
)
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.list_field[2].string_field, "hello world")
assert doc.embedded_field.list_field[2].string_field == "hello world"
# Test list native methods
doc.embedded_field.list_field[2].list_field.pop(0)
self.assertEqual(
doc._delta(),
({"embedded_field.list_field.2.list_field": [2, {"hello": "world"}]}, {}),
assert doc._delta() == (
{"embedded_field.list_field.2.list_field": [2, {"hello": "world"}]},
{},
)
doc.save()
doc = doc.reload(10)
doc.embedded_field.list_field[2].list_field.append(1)
self.assertEqual(
doc._delta(),
(
{"embedded_field.list_field.2.list_field": [2, {"hello": "world"}, 1]},
{},
),
assert doc._delta() == (
{"embedded_field.list_field.2.list_field": [2, {"hello": "world"}, 1]},
{},
)
doc.save()
doc = doc.reload(10)
self.assertEqual(
doc.embedded_field.list_field[2].list_field, [2, {"hello": "world"}, 1]
)
assert doc.embedded_field.list_field[2].list_field == [2, {"hello": "world"}, 1]
doc.embedded_field.list_field[2].list_field.sort(key=str)
doc.save()
doc = doc.reload(10)
self.assertEqual(
doc.embedded_field.list_field[2].list_field, [1, 2, {"hello": "world"}]
)
assert doc.embedded_field.list_field[2].list_field == [1, 2, {"hello": "world"}]
del doc.embedded_field.list_field[2].list_field[2]["hello"]
self.assertEqual(
doc._delta(), ({}, {"embedded_field.list_field.2.list_field.2.hello": 1})
assert doc._delta() == (
{},
{"embedded_field.list_field.2.list_field.2.hello": 1},
)
doc.save()
doc = doc.reload(10)
del doc.embedded_field.list_field[2].list_field
self.assertEqual(
doc._delta(), ({}, {"embedded_field.list_field.2.list_field": 1})
)
assert doc._delta() == ({}, {"embedded_field.list_field.2.list_field": 1})
doc.save()
doc = doc.reload(10)
@ -302,12 +282,8 @@ class TestDelta(MongoDBTestCase):
doc = doc.reload(10)
doc.dict_field["Embedded"].string_field = "Hello World"
self.assertEqual(
doc._get_changed_fields(), ["dict_field.Embedded.string_field"]
)
self.assertEqual(
doc._delta(), ({"dict_field.Embedded.string_field": "Hello World"}, {})
)
assert doc._get_changed_fields() == ["dict_field.Embedded.string_field"]
assert doc._delta() == ({"dict_field.Embedded.string_field": "Hello World"}, {})
def test_circular_reference_deltas(self):
self.circular_reference_deltas(Document, Document)
@ -338,8 +314,8 @@ class TestDelta(MongoDBTestCase):
p = Person.objects[0].select_related()
o = Organization.objects.first()
self.assertEqual(p.owns[0], o)
self.assertEqual(o.owner, p)
assert p.owns[0] == o
assert o.owner == p
def test_circular_reference_deltas_2(self):
self.circular_reference_deltas_2(Document, Document)
@ -379,9 +355,9 @@ class TestDelta(MongoDBTestCase):
e = Person.objects.get(name="employee")
o = Organization.objects.first()
self.assertEqual(p.owns[0], o)
self.assertEqual(o.owner, p)
self.assertEqual(e.employer, o)
assert p.owns[0] == o
assert o.owner == p
assert e.employer == o
return person, organization, employee
@ -401,40 +377,40 @@ class TestDelta(MongoDBTestCase):
doc.save()
doc = Doc.objects.first()
self.assertEqual(doc._get_changed_fields(), [])
self.assertEqual(doc._delta(), ({}, {}))
assert doc._get_changed_fields() == []
assert doc._delta() == ({}, {})
doc.string_field = "hello"
self.assertEqual(doc._get_changed_fields(), ["db_string_field"])
self.assertEqual(doc._delta(), ({"db_string_field": "hello"}, {}))
assert doc._get_changed_fields() == ["db_string_field"]
assert doc._delta() == ({"db_string_field": "hello"}, {})
doc._changed_fields = []
doc.int_field = 1
self.assertEqual(doc._get_changed_fields(), ["db_int_field"])
self.assertEqual(doc._delta(), ({"db_int_field": 1}, {}))
assert doc._get_changed_fields() == ["db_int_field"]
assert doc._delta() == ({"db_int_field": 1}, {})
doc._changed_fields = []
dict_value = {"hello": "world", "ping": "pong"}
doc.dict_field = dict_value
self.assertEqual(doc._get_changed_fields(), ["db_dict_field"])
self.assertEqual(doc._delta(), ({"db_dict_field": dict_value}, {}))
assert doc._get_changed_fields() == ["db_dict_field"]
assert doc._delta() == ({"db_dict_field": dict_value}, {})
doc._changed_fields = []
list_value = ["1", 2, {"hello": "world"}]
doc.list_field = list_value
self.assertEqual(doc._get_changed_fields(), ["db_list_field"])
self.assertEqual(doc._delta(), ({"db_list_field": list_value}, {}))
assert doc._get_changed_fields() == ["db_list_field"]
assert doc._delta() == ({"db_list_field": list_value}, {})
# Test unsetting
doc._changed_fields = []
doc.dict_field = {}
self.assertEqual(doc._get_changed_fields(), ["db_dict_field"])
self.assertEqual(doc._delta(), ({}, {"db_dict_field": 1}))
assert doc._get_changed_fields() == ["db_dict_field"]
assert doc._delta() == ({}, {"db_dict_field": 1})
doc._changed_fields = []
doc.list_field = []
self.assertEqual(doc._get_changed_fields(), ["db_list_field"])
self.assertEqual(doc._delta(), ({}, {"db_list_field": 1}))
assert doc._get_changed_fields() == ["db_list_field"]
assert doc._delta() == ({}, {"db_list_field": 1})
# Test it saves that data
doc = Doc()
@ -447,10 +423,10 @@ class TestDelta(MongoDBTestCase):
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.string_field, "hello")
self.assertEqual(doc.int_field, 1)
self.assertEqual(doc.dict_field, {"hello": "world"})
self.assertEqual(doc.list_field, ["1", 2, {"hello": "world"}])
assert doc.string_field == "hello"
assert doc.int_field == 1
assert doc.dict_field == {"hello": "world"}
assert doc.list_field == ["1", 2, {"hello": "world"}]
def test_delta_recursive_db_field(self):
self.delta_recursive_db_field(Document, EmbeddedDocument)
@ -479,8 +455,8 @@ class TestDelta(MongoDBTestCase):
doc.save()
doc = Doc.objects.first()
self.assertEqual(doc._get_changed_fields(), [])
self.assertEqual(doc._delta(), ({}, {}))
assert doc._get_changed_fields() == []
assert doc._delta() == ({}, {})
embedded_1 = Embedded()
embedded_1.string_field = "hello"
@ -489,7 +465,7 @@ class TestDelta(MongoDBTestCase):
embedded_1.list_field = ["1", 2, {"hello": "world"}]
doc.embedded_field = embedded_1
self.assertEqual(doc._get_changed_fields(), ["db_embedded_field"])
assert doc._get_changed_fields() == ["db_embedded_field"]
embedded_delta = {
"db_string_field": "hello",
@ -497,27 +473,27 @@ class TestDelta(MongoDBTestCase):
"db_dict_field": {"hello": "world"},
"db_list_field": ["1", 2, {"hello": "world"}],
}
self.assertEqual(doc.embedded_field._delta(), (embedded_delta, {}))
self.assertEqual(doc._delta(), ({"db_embedded_field": embedded_delta}, {}))
assert doc.embedded_field._delta() == (embedded_delta, {})
assert doc._delta() == ({"db_embedded_field": embedded_delta}, {})
doc.save()
doc = doc.reload(10)
doc.embedded_field.dict_field = {}
self.assertEqual(doc._get_changed_fields(), ["db_embedded_field.db_dict_field"])
self.assertEqual(doc.embedded_field._delta(), ({}, {"db_dict_field": 1}))
self.assertEqual(doc._delta(), ({}, {"db_embedded_field.db_dict_field": 1}))
assert doc._get_changed_fields() == ["db_embedded_field.db_dict_field"]
assert doc.embedded_field._delta() == ({}, {"db_dict_field": 1})
assert doc._delta() == ({}, {"db_embedded_field.db_dict_field": 1})
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.dict_field, {})
assert doc.embedded_field.dict_field == {}
doc.embedded_field.list_field = []
self.assertEqual(doc._get_changed_fields(), ["db_embedded_field.db_list_field"])
self.assertEqual(doc.embedded_field._delta(), ({}, {"db_list_field": 1}))
self.assertEqual(doc._delta(), ({}, {"db_embedded_field.db_list_field": 1}))
assert doc._get_changed_fields() == ["db_embedded_field.db_list_field"]
assert doc.embedded_field._delta() == ({}, {"db_list_field": 1})
assert doc._delta() == ({}, {"db_embedded_field.db_list_field": 1})
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.list_field, [])
assert doc.embedded_field.list_field == []
embedded_2 = Embedded()
embedded_2.string_field = "hello"
@ -526,166 +502,142 @@ class TestDelta(MongoDBTestCase):
embedded_2.list_field = ["1", 2, {"hello": "world"}]
doc.embedded_field.list_field = ["1", 2, embedded_2]
self.assertEqual(doc._get_changed_fields(), ["db_embedded_field.db_list_field"])
self.assertEqual(
doc.embedded_field._delta(),
(
{
"db_list_field": [
"1",
2,
{
"_cls": "Embedded",
"db_string_field": "hello",
"db_dict_field": {"hello": "world"},
"db_int_field": 1,
"db_list_field": ["1", 2, {"hello": "world"}],
},
]
},
{},
),
assert doc._get_changed_fields() == ["db_embedded_field.db_list_field"]
assert doc.embedded_field._delta() == (
{
"db_list_field": [
"1",
2,
{
"_cls": "Embedded",
"db_string_field": "hello",
"db_dict_field": {"hello": "world"},
"db_int_field": 1,
"db_list_field": ["1", 2, {"hello": "world"}],
},
]
},
{},
)
self.assertEqual(
doc._delta(),
(
{
"db_embedded_field.db_list_field": [
"1",
2,
{
"_cls": "Embedded",
"db_string_field": "hello",
"db_dict_field": {"hello": "world"},
"db_int_field": 1,
"db_list_field": ["1", 2, {"hello": "world"}],
},
]
},
{},
),
assert doc._delta() == (
{
"db_embedded_field.db_list_field": [
"1",
2,
{
"_cls": "Embedded",
"db_string_field": "hello",
"db_dict_field": {"hello": "world"},
"db_int_field": 1,
"db_list_field": ["1", 2, {"hello": "world"}],
},
]
},
{},
)
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.list_field[0], "1")
self.assertEqual(doc.embedded_field.list_field[1], 2)
assert doc.embedded_field.list_field[0] == "1"
assert doc.embedded_field.list_field[1] == 2
for k in doc.embedded_field.list_field[2]._fields:
self.assertEqual(doc.embedded_field.list_field[2][k], embedded_2[k])
assert doc.embedded_field.list_field[2][k] == embedded_2[k]
doc.embedded_field.list_field[2].string_field = "world"
self.assertEqual(
doc._get_changed_fields(),
["db_embedded_field.db_list_field.2.db_string_field"],
assert doc._get_changed_fields() == [
"db_embedded_field.db_list_field.2.db_string_field"
]
assert doc.embedded_field._delta() == (
{"db_list_field.2.db_string_field": "world"},
{},
)
self.assertEqual(
doc.embedded_field._delta(),
({"db_list_field.2.db_string_field": "world"}, {}),
)
self.assertEqual(
doc._delta(),
({"db_embedded_field.db_list_field.2.db_string_field": "world"}, {}),
assert doc._delta() == (
{"db_embedded_field.db_list_field.2.db_string_field": "world"},
{},
)
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.list_field[2].string_field, "world")
assert doc.embedded_field.list_field[2].string_field == "world"
# Test multiple assignments
doc.embedded_field.list_field[2].string_field = "hello world"
doc.embedded_field.list_field[2] = doc.embedded_field.list_field[2]
self.assertEqual(
doc._get_changed_fields(), ["db_embedded_field.db_list_field.2"]
assert doc._get_changed_fields() == ["db_embedded_field.db_list_field.2"]
assert doc.embedded_field._delta() == (
{
"db_list_field.2": {
"_cls": "Embedded",
"db_string_field": "hello world",
"db_int_field": 1,
"db_list_field": ["1", 2, {"hello": "world"}],
"db_dict_field": {"hello": "world"},
}
},
{},
)
self.assertEqual(
doc.embedded_field._delta(),
(
{
"db_list_field.2": {
"_cls": "Embedded",
"db_string_field": "hello world",
"db_int_field": 1,
"db_list_field": ["1", 2, {"hello": "world"}],
"db_dict_field": {"hello": "world"},
}
},
{},
),
)
self.assertEqual(
doc._delta(),
(
{
"db_embedded_field.db_list_field.2": {
"_cls": "Embedded",
"db_string_field": "hello world",
"db_int_field": 1,
"db_list_field": ["1", 2, {"hello": "world"}],
"db_dict_field": {"hello": "world"},
}
},
{},
),
assert doc._delta() == (
{
"db_embedded_field.db_list_field.2": {
"_cls": "Embedded",
"db_string_field": "hello world",
"db_int_field": 1,
"db_list_field": ["1", 2, {"hello": "world"}],
"db_dict_field": {"hello": "world"},
}
},
{},
)
doc.save()
doc = doc.reload(10)
self.assertEqual(doc.embedded_field.list_field[2].string_field, "hello world")
assert doc.embedded_field.list_field[2].string_field == "hello world"
# Test list native methods
doc.embedded_field.list_field[2].list_field.pop(0)
self.assertEqual(
doc._delta(),
(
{
"db_embedded_field.db_list_field.2.db_list_field": [
2,
{"hello": "world"},
]
},
{},
),
assert doc._delta() == (
{
"db_embedded_field.db_list_field.2.db_list_field": [
2,
{"hello": "world"},
]
},
{},
)
doc.save()
doc = doc.reload(10)
doc.embedded_field.list_field[2].list_field.append(1)
self.assertEqual(
doc._delta(),
(
{
"db_embedded_field.db_list_field.2.db_list_field": [
2,
{"hello": "world"},
1,
]
},
{},
),
assert doc._delta() == (
{
"db_embedded_field.db_list_field.2.db_list_field": [
2,
{"hello": "world"},
1,
]
},
{},
)
doc.save()
doc = doc.reload(10)
self.assertEqual(
doc.embedded_field.list_field[2].list_field, [2, {"hello": "world"}, 1]
)
assert doc.embedded_field.list_field[2].list_field == [2, {"hello": "world"}, 1]
doc.embedded_field.list_field[2].list_field.sort(key=str)
doc.save()
doc = doc.reload(10)
self.assertEqual(
doc.embedded_field.list_field[2].list_field, [1, 2, {"hello": "world"}]
)
assert doc.embedded_field.list_field[2].list_field == [1, 2, {"hello": "world"}]
del doc.embedded_field.list_field[2].list_field[2]["hello"]
self.assertEqual(
doc._delta(),
({}, {"db_embedded_field.db_list_field.2.db_list_field.2.hello": 1}),
assert doc._delta() == (
{},
{"db_embedded_field.db_list_field.2.db_list_field.2.hello": 1},
)
doc.save()
doc = doc.reload(10)
del doc.embedded_field.list_field[2].list_field
self.assertEqual(
doc._delta(), ({}, {"db_embedded_field.db_list_field.2.db_list_field": 1})
assert doc._delta() == (
{},
{"db_embedded_field.db_list_field.2.db_list_field": 1},
)
def test_delta_for_dynamic_documents(self):
@ -696,14 +648,16 @@ class TestDelta(MongoDBTestCase):
Person.drop_collection()
p = Person(name="James", age=34)
self.assertEqual(
p._delta(), (SON([("_cls", "Person"), ("name", "James"), ("age", 34)]), {})
assert p._delta() == (
SON([("_cls", "Person"), ("name", "James"), ("age", 34)]),
{},
)
p.doc = 123
del p.doc
self.assertEqual(
p._delta(), (SON([("_cls", "Person"), ("name", "James"), ("age", 34)]), {})
assert p._delta() == (
SON([("_cls", "Person"), ("name", "James"), ("age", 34)]),
{},
)
p = Person()
@ -712,18 +666,18 @@ class TestDelta(MongoDBTestCase):
p.save()
p.age = 24
self.assertEqual(p.age, 24)
self.assertEqual(p._get_changed_fields(), ["age"])
self.assertEqual(p._delta(), ({"age": 24}, {}))
assert p.age == 24
assert p._get_changed_fields() == ["age"]
assert p._delta() == ({"age": 24}, {})
p = Person.objects(age=22).get()
p.age = 24
self.assertEqual(p.age, 24)
self.assertEqual(p._get_changed_fields(), ["age"])
self.assertEqual(p._delta(), ({"age": 24}, {}))
assert p.age == 24
assert p._get_changed_fields() == ["age"]
assert p._delta() == ({"age": 24}, {})
p.save()
self.assertEqual(1, Person.objects(age=24).count())
assert 1 == Person.objects(age=24).count()
def test_dynamic_delta(self):
class Doc(DynamicDocument):
@ -734,40 +688,40 @@ class TestDelta(MongoDBTestCase):
doc.save()
doc = Doc.objects.first()
self.assertEqual(doc._get_changed_fields(), [])
self.assertEqual(doc._delta(), ({}, {}))
assert doc._get_changed_fields() == []
assert doc._delta() == ({}, {})
doc.string_field = "hello"
self.assertEqual(doc._get_changed_fields(), ["string_field"])
self.assertEqual(doc._delta(), ({"string_field": "hello"}, {}))
assert doc._get_changed_fields() == ["string_field"]
assert doc._delta() == ({"string_field": "hello"}, {})
doc._changed_fields = []
doc.int_field = 1
self.assertEqual(doc._get_changed_fields(), ["int_field"])
self.assertEqual(doc._delta(), ({"int_field": 1}, {}))
assert doc._get_changed_fields() == ["int_field"]
assert doc._delta() == ({"int_field": 1}, {})
doc._changed_fields = []
dict_value = {"hello": "world", "ping": "pong"}
doc.dict_field = dict_value
self.assertEqual(doc._get_changed_fields(), ["dict_field"])
self.assertEqual(doc._delta(), ({"dict_field": dict_value}, {}))
assert doc._get_changed_fields() == ["dict_field"]
assert doc._delta() == ({"dict_field": dict_value}, {})
doc._changed_fields = []
list_value = ["1", 2, {"hello": "world"}]
doc.list_field = list_value
self.assertEqual(doc._get_changed_fields(), ["list_field"])
self.assertEqual(doc._delta(), ({"list_field": list_value}, {}))
assert doc._get_changed_fields() == ["list_field"]
assert doc._delta() == ({"list_field": list_value}, {})
# Test unsetting
doc._changed_fields = []
doc.dict_field = {}
self.assertEqual(doc._get_changed_fields(), ["dict_field"])
self.assertEqual(doc._delta(), ({}, {"dict_field": 1}))
assert doc._get_changed_fields() == ["dict_field"]
assert doc._delta() == ({}, {"dict_field": 1})
doc._changed_fields = []
doc.list_field = []
self.assertEqual(doc._get_changed_fields(), ["list_field"])
self.assertEqual(doc._delta(), ({}, {"list_field": 1}))
assert doc._get_changed_fields() == ["list_field"]
assert doc._delta() == ({}, {"list_field": 1})
def test_delta_with_dbref_true(self):
person, organization, employee = self.circular_reference_deltas_2(
@ -775,16 +729,16 @@ class TestDelta(MongoDBTestCase):
)
employee.name = "test"
self.assertEqual(organization._get_changed_fields(), [])
assert organization._get_changed_fields() == []
updates, removals = organization._delta()
self.assertEqual({}, removals)
self.assertEqual({}, updates)
assert {} == removals
assert {} == updates
organization.employees.append(person)
updates, removals = organization._delta()
self.assertEqual({}, removals)
self.assertIn("employees", updates)
assert {} == removals
assert "employees" in updates
def test_delta_with_dbref_false(self):
person, organization, employee = self.circular_reference_deltas_2(
@ -792,16 +746,16 @@ class TestDelta(MongoDBTestCase):
)
employee.name = "test"
self.assertEqual(organization._get_changed_fields(), [])
assert organization._get_changed_fields() == []
updates, removals = organization._delta()
self.assertEqual({}, removals)
self.assertEqual({}, updates)
assert {} == removals
assert {} == updates
organization.employees.append(person)
updates, removals = organization._delta()
self.assertEqual({}, removals)
self.assertIn("employees", updates)
assert {} == removals
assert "employees" in updates
def test_nested_nested_fields_mark_as_changed(self):
class EmbeddedDoc(EmbeddedDocument):
@ -821,11 +775,11 @@ class TestDelta(MongoDBTestCase):
subdoc = mydoc.subs["a"]["b"]
subdoc.name = "bar"
self.assertEqual(["name"], subdoc._get_changed_fields())
self.assertEqual(["subs.a.b.name"], mydoc._get_changed_fields())
assert ["name"] == subdoc._get_changed_fields()
assert ["subs.a.b.name"] == mydoc._get_changed_fields()
mydoc._clear_changed_fields()
self.assertEqual([], mydoc._get_changed_fields())
assert [] == mydoc._get_changed_fields()
def test_lower_level_mark_as_changed(self):
class EmbeddedDoc(EmbeddedDocument):
@ -840,17 +794,17 @@ class TestDelta(MongoDBTestCase):
mydoc = MyDoc.objects.first()
mydoc.subs["a"] = EmbeddedDoc()
self.assertEqual(["subs.a"], mydoc._get_changed_fields())
assert ["subs.a"] == mydoc._get_changed_fields()
subdoc = mydoc.subs["a"]
subdoc.name = "bar"
self.assertEqual(["name"], subdoc._get_changed_fields())
self.assertEqual(["subs.a"], mydoc._get_changed_fields())
assert ["name"] == subdoc._get_changed_fields()
assert ["subs.a"] == mydoc._get_changed_fields()
mydoc.save()
mydoc._clear_changed_fields()
self.assertEqual([], mydoc._get_changed_fields())
assert [] == mydoc._get_changed_fields()
def test_upper_level_mark_as_changed(self):
class EmbeddedDoc(EmbeddedDocument):
@ -867,15 +821,15 @@ class TestDelta(MongoDBTestCase):
subdoc = mydoc.subs["a"]
subdoc.name = "bar"
self.assertEqual(["name"], subdoc._get_changed_fields())
self.assertEqual(["subs.a.name"], mydoc._get_changed_fields())
assert ["name"] == subdoc._get_changed_fields()
assert ["subs.a.name"] == mydoc._get_changed_fields()
mydoc.subs["a"] = EmbeddedDoc()
self.assertEqual(["subs.a"], mydoc._get_changed_fields())
assert ["subs.a"] == mydoc._get_changed_fields()
mydoc.save()
mydoc._clear_changed_fields()
self.assertEqual([], mydoc._get_changed_fields())
assert [] == mydoc._get_changed_fields()
def test_referenced_object_changed_attributes(self):
"""Ensures that when you save a new reference to a field, the referenced object isn't altered"""
@ -902,22 +856,22 @@ class TestDelta(MongoDBTestCase):
org1.reload()
org2.reload()
user.reload()
self.assertEqual(org1.name, "Org 1")
self.assertEqual(org2.name, "Org 2")
self.assertEqual(user.name, "Fred")
assert org1.name == "Org 1"
assert org2.name == "Org 2"
assert user.name == "Fred"
user.name = "Harold"
user.org = org2
org2.name = "New Org 2"
self.assertEqual(org2.name, "New Org 2")
assert org2.name == "New Org 2"
user.save()
org2.save()
self.assertEqual(org2.name, "New Org 2")
assert org2.name == "New Org 2"
org2.reload()
self.assertEqual(org2.name, "New Org 2")
assert org2.name == "New Org 2"
def test_delta_for_nested_map_fields(self):
class UInfoDocument(Document):
@ -950,12 +904,12 @@ class TestDelta(MongoDBTestCase):
d.users["007"]["rolist"].append(EmbeddedRole(type="oops"))
d.users["007"]["info"] = uinfo
delta = d._delta()
self.assertEqual(True, "users.007.roles.666" in delta[0])
self.assertEqual(True, "users.007.rolist" in delta[0])
self.assertEqual(True, "users.007.info" in delta[0])
self.assertEqual("superadmin", delta[0]["users.007.roles.666"]["type"])
self.assertEqual("oops", delta[0]["users.007.rolist"][0]["type"])
self.assertEqual(uinfo.id, delta[0]["users.007.info"])
assert True == ("users.007.roles.666" in delta[0])
assert True == ("users.007.rolist" in delta[0])
assert True == ("users.007.info" in delta[0])
assert "superadmin" == delta[0]["users.007.roles.666"]["type"]
assert "oops" == delta[0]["users.007.rolist"][0]["type"]
assert uinfo.id == delta[0]["users.007.info"]
if __name__ == "__main__":

View File

@ -1,5 +1,7 @@
import unittest
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -25,15 +27,15 @@ class TestDynamicDocument(MongoDBTestCase):
p.name = "James"
p.age = 34
self.assertEqual(p.to_mongo(), {"_cls": "Person", "name": "James", "age": 34})
self.assertEqual(p.to_mongo().keys(), ["_cls", "name", "age"])
assert p.to_mongo() == {"_cls": "Person", "name": "James", "age": 34}
assert p.to_mongo().keys() == ["_cls", "name", "age"]
p.save()
self.assertEqual(p.to_mongo().keys(), ["_id", "_cls", "name", "age"])
assert p.to_mongo().keys() == ["_id", "_cls", "name", "age"]
self.assertEqual(self.Person.objects.first().age, 34)
assert self.Person.objects.first().age == 34
# Confirm no changes to self.Person
self.assertFalse(hasattr(self.Person, "age"))
assert not hasattr(self.Person, "age")
def test_change_scope_of_variable(self):
"""Test changing the scope of a dynamic field has no adverse effects"""
@ -47,7 +49,7 @@ class TestDynamicDocument(MongoDBTestCase):
p.save()
p = self.Person.objects.get()
self.assertEqual(p.misc, {"hello": "world"})
assert p.misc == {"hello": "world"}
def test_delete_dynamic_field(self):
"""Test deleting a dynamic field works"""
@ -62,19 +64,19 @@ class TestDynamicDocument(MongoDBTestCase):
p.save()
p = self.Person.objects.get()
self.assertEqual(p.misc, {"hello": "world"})
assert p.misc == {"hello": "world"}
collection = self.db[self.Person._get_collection_name()]
obj = collection.find_one()
self.assertEqual(sorted(obj.keys()), ["_cls", "_id", "misc", "name"])
assert sorted(obj.keys()) == ["_cls", "_id", "misc", "name"]
del p.misc
p.save()
p = self.Person.objects.get()
self.assertFalse(hasattr(p, "misc"))
assert not hasattr(p, "misc")
obj = collection.find_one()
self.assertEqual(sorted(obj.keys()), ["_cls", "_id", "name"])
assert sorted(obj.keys()) == ["_cls", "_id", "name"]
def test_reload_after_unsetting(self):
p = self.Person()
@ -88,12 +90,12 @@ class TestDynamicDocument(MongoDBTestCase):
p = self.Person.objects.create()
p.update(age=1)
self.assertEqual(len(p._data), 3)
self.assertEqual(sorted(p._data.keys()), ["_cls", "id", "name"])
assert len(p._data) == 3
assert sorted(p._data.keys()) == ["_cls", "id", "name"]
p.reload()
self.assertEqual(len(p._data), 4)
self.assertEqual(sorted(p._data.keys()), ["_cls", "age", "id", "name"])
assert len(p._data) == 4
assert sorted(p._data.keys()) == ["_cls", "age", "id", "name"]
def test_fields_without_underscore(self):
"""Ensure we can query dynamic fields"""
@ -103,16 +105,18 @@ class TestDynamicDocument(MongoDBTestCase):
p.save()
raw_p = Person.objects.as_pymongo().get(id=p.id)
self.assertEqual(raw_p, {"_cls": u"Person", "_id": p.id, "name": u"Dean"})
assert raw_p == {"_cls": u"Person", "_id": p.id, "name": u"Dean"}
p.name = "OldDean"
p.newattr = "garbage"
p.save()
raw_p = Person.objects.as_pymongo().get(id=p.id)
self.assertEqual(
raw_p,
{"_cls": u"Person", "_id": p.id, "name": "OldDean", "newattr": u"garbage"},
)
assert raw_p == {
"_cls": u"Person",
"_id": p.id,
"name": "OldDean",
"newattr": u"garbage",
}
def test_fields_containing_underscore(self):
"""Ensure we can query dynamic fields"""
@ -127,14 +131,14 @@ class TestDynamicDocument(MongoDBTestCase):
p.save()
raw_p = WeirdPerson.objects.as_pymongo().get(id=p.id)
self.assertEqual(raw_p, {"_id": p.id, "_name": u"Dean", "name": u"Dean"})
assert raw_p == {"_id": p.id, "_name": u"Dean", "name": u"Dean"}
p.name = "OldDean"
p._name = "NewDean"
p._newattr1 = "garbage" # Unknown fields won't be added
p.save()
raw_p = WeirdPerson.objects.as_pymongo().get(id=p.id)
self.assertEqual(raw_p, {"_id": p.id, "_name": u"NewDean", "name": u"OldDean"})
assert raw_p == {"_id": p.id, "_name": u"NewDean", "name": u"OldDean"}
def test_dynamic_document_queries(self):
"""Ensure we can query dynamic fields"""
@ -143,10 +147,10 @@ class TestDynamicDocument(MongoDBTestCase):
p.age = 22
p.save()
self.assertEqual(1, self.Person.objects(age=22).count())
assert 1 == self.Person.objects(age=22).count()
p = self.Person.objects(age=22)
p = p.get()
self.assertEqual(22, p.age)
assert 22 == p.age
def test_complex_dynamic_document_queries(self):
class Person(DynamicDocument):
@ -166,8 +170,8 @@ class TestDynamicDocument(MongoDBTestCase):
p2.age = 10
p2.save()
self.assertEqual(Person.objects(age__icontains="ten").count(), 2)
self.assertEqual(Person.objects(age__gte=10).count(), 1)
assert Person.objects(age__icontains="ten").count() == 2
assert Person.objects(age__gte=10).count() == 1
def test_complex_data_lookups(self):
"""Ensure you can query dynamic document dynamic fields"""
@ -175,12 +179,12 @@ class TestDynamicDocument(MongoDBTestCase):
p.misc = {"hello": "world"}
p.save()
self.assertEqual(1, self.Person.objects(misc__hello="world").count())
assert 1 == self.Person.objects(misc__hello="world").count()
def test_three_level_complex_data_lookups(self):
"""Ensure you can query three level document dynamic fields"""
self.Person.objects.create(misc={"hello": {"hello2": "world"}})
self.assertEqual(1, self.Person.objects(misc__hello__hello2="world").count())
assert 1 == self.Person.objects(misc__hello__hello2="world").count()
def test_complex_embedded_document_validation(self):
"""Ensure embedded dynamic documents may be validated"""
@ -198,11 +202,13 @@ class TestDynamicDocument(MongoDBTestCase):
embedded_doc_1.validate()
embedded_doc_2 = Embedded(content="this is not a url")
self.assertRaises(ValidationError, embedded_doc_2.validate)
with pytest.raises(ValidationError):
embedded_doc_2.validate()
doc.embedded_field_1 = embedded_doc_1
doc.embedded_field_2 = embedded_doc_2
self.assertRaises(ValidationError, doc.validate)
with pytest.raises(ValidationError):
doc.validate()
def test_inheritance(self):
"""Ensure that dynamic document plays nice with inheritance"""
@ -212,11 +218,9 @@ class TestDynamicDocument(MongoDBTestCase):
Employee.drop_collection()
self.assertIn("name", Employee._fields)
self.assertIn("salary", Employee._fields)
self.assertEqual(
Employee._get_collection_name(), self.Person._get_collection_name()
)
assert "name" in Employee._fields
assert "salary" in Employee._fields
assert Employee._get_collection_name() == self.Person._get_collection_name()
joe_bloggs = Employee()
joe_bloggs.name = "Joe Bloggs"
@ -224,11 +228,11 @@ class TestDynamicDocument(MongoDBTestCase):
joe_bloggs.age = 20
joe_bloggs.save()
self.assertEqual(1, self.Person.objects(age=20).count())
self.assertEqual(1, Employee.objects(age=20).count())
assert 1 == self.Person.objects(age=20).count()
assert 1 == Employee.objects(age=20).count()
joe_bloggs = self.Person.objects.first()
self.assertIsInstance(joe_bloggs, Employee)
assert isinstance(joe_bloggs, Employee)
def test_embedded_dynamic_document(self):
"""Test dynamic embedded documents"""
@ -249,26 +253,23 @@ class TestDynamicDocument(MongoDBTestCase):
embedded_1.list_field = ["1", 2, {"hello": "world"}]
doc.embedded_field = embedded_1
self.assertEqual(
doc.to_mongo(),
{
"embedded_field": {
"_cls": "Embedded",
"string_field": "hello",
"int_field": 1,
"dict_field": {"hello": "world"},
"list_field": ["1", 2, {"hello": "world"}],
}
},
)
assert doc.to_mongo() == {
"embedded_field": {
"_cls": "Embedded",
"string_field": "hello",
"int_field": 1,
"dict_field": {"hello": "world"},
"list_field": ["1", 2, {"hello": "world"}],
}
}
doc.save()
doc = Doc.objects.first()
self.assertEqual(doc.embedded_field.__class__, Embedded)
self.assertEqual(doc.embedded_field.string_field, "hello")
self.assertEqual(doc.embedded_field.int_field, 1)
self.assertEqual(doc.embedded_field.dict_field, {"hello": "world"})
self.assertEqual(doc.embedded_field.list_field, ["1", 2, {"hello": "world"}])
assert doc.embedded_field.__class__ == Embedded
assert doc.embedded_field.string_field == "hello"
assert doc.embedded_field.int_field == 1
assert doc.embedded_field.dict_field == {"hello": "world"}
assert doc.embedded_field.list_field == ["1", 2, {"hello": "world"}]
def test_complex_embedded_documents(self):
"""Test complex dynamic embedded documents setups"""
@ -296,44 +297,41 @@ class TestDynamicDocument(MongoDBTestCase):
embedded_1.list_field = ["1", 2, embedded_2]
doc.embedded_field = embedded_1
self.assertEqual(
doc.to_mongo(),
{
"embedded_field": {
"_cls": "Embedded",
"string_field": "hello",
"int_field": 1,
"dict_field": {"hello": "world"},
"list_field": [
"1",
2,
{
"_cls": "Embedded",
"string_field": "hello",
"int_field": 1,
"dict_field": {"hello": "world"},
"list_field": ["1", 2, {"hello": "world"}],
},
],
}
},
)
assert doc.to_mongo() == {
"embedded_field": {
"_cls": "Embedded",
"string_field": "hello",
"int_field": 1,
"dict_field": {"hello": "world"},
"list_field": [
"1",
2,
{
"_cls": "Embedded",
"string_field": "hello",
"int_field": 1,
"dict_field": {"hello": "world"},
"list_field": ["1", 2, {"hello": "world"}],
},
],
}
}
doc.save()
doc = Doc.objects.first()
self.assertEqual(doc.embedded_field.__class__, Embedded)
self.assertEqual(doc.embedded_field.string_field, "hello")
self.assertEqual(doc.embedded_field.int_field, 1)
self.assertEqual(doc.embedded_field.dict_field, {"hello": "world"})
self.assertEqual(doc.embedded_field.list_field[0], "1")
self.assertEqual(doc.embedded_field.list_field[1], 2)
assert doc.embedded_field.__class__ == Embedded
assert doc.embedded_field.string_field == "hello"
assert doc.embedded_field.int_field == 1
assert doc.embedded_field.dict_field == {"hello": "world"}
assert doc.embedded_field.list_field[0] == "1"
assert doc.embedded_field.list_field[1] == 2
embedded_field = doc.embedded_field.list_field[2]
self.assertEqual(embedded_field.__class__, Embedded)
self.assertEqual(embedded_field.string_field, "hello")
self.assertEqual(embedded_field.int_field, 1)
self.assertEqual(embedded_field.dict_field, {"hello": "world"})
self.assertEqual(embedded_field.list_field, ["1", 2, {"hello": "world"}])
assert embedded_field.__class__ == Embedded
assert embedded_field.string_field == "hello"
assert embedded_field.int_field == 1
assert embedded_field.dict_field == {"hello": "world"}
assert embedded_field.list_field == ["1", 2, {"hello": "world"}]
def test_dynamic_and_embedded(self):
"""Ensure embedded documents play nicely"""
@ -352,18 +350,18 @@ class TestDynamicDocument(MongoDBTestCase):
person.address.city = "Lundenne"
person.save()
self.assertEqual(Person.objects.first().address.city, "Lundenne")
assert Person.objects.first().address.city == "Lundenne"
person = Person.objects.first()
person.address = Address(city="Londinium")
person.save()
self.assertEqual(Person.objects.first().address.city, "Londinium")
assert Person.objects.first().address.city == "Londinium"
person = Person.objects.first()
person.age = 35
person.save()
self.assertEqual(Person.objects.first().age, 35)
assert Person.objects.first().age == 35
def test_dynamic_embedded_works_with_only(self):
"""Ensure custom fieldnames on a dynamic embedded document are found by qs.only()"""
@ -380,10 +378,10 @@ class TestDynamicDocument(MongoDBTestCase):
name="Eric", address=Address(city="San Francisco", street_number="1337")
).save()
self.assertEqual(Person.objects.first().address.street_number, "1337")
self.assertEqual(
Person.objects.only("address__street_number").first().address.street_number,
"1337",
assert Person.objects.first().address.street_number == "1337"
assert (
Person.objects.only("address__street_number").first().address.street_number
== "1337"
)
def test_dynamic_and_embedded_dict_access(self):
@ -408,20 +406,20 @@ class TestDynamicDocument(MongoDBTestCase):
person["address"]["city"] = "Lundenne"
person.save()
self.assertEqual(Person.objects.first().address.city, "Lundenne")
assert Person.objects.first().address.city == "Lundenne"
self.assertEqual(Person.objects.first().phone, "555-1212")
assert Person.objects.first().phone == "555-1212"
person = Person.objects.first()
person.address = Address(city="Londinium")
person.save()
self.assertEqual(Person.objects.first().address.city, "Londinium")
assert Person.objects.first().address.city == "Londinium"
person = Person.objects.first()
person["age"] = 35
person.save()
self.assertEqual(Person.objects.first().age, 35)
assert Person.objects.first().age == 35
if __name__ == "__main__":

View File

@ -2,9 +2,9 @@
import unittest
from datetime import datetime
from nose.plugins.skip import SkipTest
from pymongo.collation import Collation
from pymongo.errors import OperationFailure
import pytest
from six import iteritems
from mongoengine import *
@ -53,15 +53,15 @@ class TestIndexes(unittest.TestCase):
{"fields": [("tags", 1)]},
{"fields": [("category", 1), ("addDate", -1)]},
]
self.assertEqual(expected_specs, BlogPost._meta["index_specs"])
assert expected_specs == BlogPost._meta["index_specs"]
BlogPost.ensure_indexes()
info = BlogPost.objects._collection.index_information()
# _id, '-date', 'tags', ('cat', 'date')
self.assertEqual(len(info), 4)
assert len(info) == 4
info = [value["key"] for key, value in iteritems(info)]
for expected in expected_specs:
self.assertIn(expected["fields"], info)
assert expected["fields"] in info
def _index_test_inheritance(self, InheritFrom):
class BlogPost(InheritFrom):
@ -78,7 +78,7 @@ class TestIndexes(unittest.TestCase):
{"fields": [("_cls", 1), ("tags", 1)]},
{"fields": [("_cls", 1), ("category", 1), ("addDate", -1)]},
]
self.assertEqual(expected_specs, BlogPost._meta["index_specs"])
assert expected_specs == BlogPost._meta["index_specs"]
BlogPost.ensure_indexes()
info = BlogPost.objects._collection.index_information()
@ -86,17 +86,17 @@ class TestIndexes(unittest.TestCase):
# NB: there is no index on _cls by itself, since
# the indices on -date and tags will both contain
# _cls as first element in the key
self.assertEqual(len(info), 4)
assert len(info) == 4
info = [value["key"] for key, value in iteritems(info)]
for expected in expected_specs:
self.assertIn(expected["fields"], info)
assert expected["fields"] in info
class ExtendedBlogPost(BlogPost):
title = StringField()
meta = {"indexes": ["title"]}
expected_specs.append({"fields": [("_cls", 1), ("title", 1)]})
self.assertEqual(expected_specs, ExtendedBlogPost._meta["index_specs"])
assert expected_specs == ExtendedBlogPost._meta["index_specs"]
BlogPost.drop_collection()
@ -104,7 +104,7 @@ class TestIndexes(unittest.TestCase):
info = ExtendedBlogPost.objects._collection.index_information()
info = [value["key"] for key, value in iteritems(info)]
for expected in expected_specs:
self.assertIn(expected["fields"], info)
assert expected["fields"] in info
def test_indexes_document_inheritance(self):
"""Ensure that indexes are used when meta[indexes] is specified for
@ -128,10 +128,8 @@ class TestIndexes(unittest.TestCase):
class B(A):
description = StringField()
self.assertEqual(A._meta["index_specs"], B._meta["index_specs"])
self.assertEqual(
[{"fields": [("_cls", 1), ("title", 1)]}], A._meta["index_specs"]
)
assert A._meta["index_specs"] == B._meta["index_specs"]
assert [{"fields": [("_cls", 1), ("title", 1)]}] == A._meta["index_specs"]
def test_index_no_cls(self):
"""Ensure index specs are inhertited correctly"""
@ -144,11 +142,11 @@ class TestIndexes(unittest.TestCase):
"index_cls": False,
}
self.assertEqual([("title", 1)], A._meta["index_specs"][0]["fields"])
assert [("title", 1)] == A._meta["index_specs"][0]["fields"]
A._get_collection().drop_indexes()
A.ensure_indexes()
info = A._get_collection().index_information()
self.assertEqual(len(info.keys()), 2)
assert len(info.keys()) == 2
class B(A):
c = StringField()
@ -158,8 +156,8 @@ class TestIndexes(unittest.TestCase):
"allow_inheritance": True,
}
self.assertEqual([("c", 1)], B._meta["index_specs"][1]["fields"])
self.assertEqual([("_cls", 1), ("d", 1)], B._meta["index_specs"][2]["fields"])
assert [("c", 1)] == B._meta["index_specs"][1]["fields"]
assert [("_cls", 1), ("d", 1)] == B._meta["index_specs"][2]["fields"]
def test_build_index_spec_is_not_destructive(self):
class MyDoc(Document):
@ -167,12 +165,12 @@ class TestIndexes(unittest.TestCase):
meta = {"indexes": ["keywords"], "allow_inheritance": False}
self.assertEqual(MyDoc._meta["index_specs"], [{"fields": [("keywords", 1)]}])
assert MyDoc._meta["index_specs"] == [{"fields": [("keywords", 1)]}]
# Force index creation
MyDoc.ensure_indexes()
self.assertEqual(MyDoc._meta["index_specs"], [{"fields": [("keywords", 1)]}])
assert MyDoc._meta["index_specs"] == [{"fields": [("keywords", 1)]}]
def test_embedded_document_index_meta(self):
"""Ensure that embedded document indexes are created explicitly
@ -187,7 +185,7 @@ class TestIndexes(unittest.TestCase):
meta = {"indexes": ["rank.title"], "allow_inheritance": False}
self.assertEqual([{"fields": [("rank.title", 1)]}], Person._meta["index_specs"])
assert [{"fields": [("rank.title", 1)]}] == Person._meta["index_specs"]
Person.drop_collection()
@ -195,7 +193,7 @@ class TestIndexes(unittest.TestCase):
list(Person.objects)
info = Person.objects._collection.index_information()
info = [value["key"] for key, value in iteritems(info)]
self.assertIn([("rank.title", 1)], info)
assert [("rank.title", 1)] in info
def test_explicit_geo2d_index(self):
"""Ensure that geo2d indexes work when created via meta[indexes]
@ -205,14 +203,12 @@ class TestIndexes(unittest.TestCase):
location = DictField()
meta = {"allow_inheritance": True, "indexes": ["*location.point"]}
self.assertEqual(
[{"fields": [("location.point", "2d")]}], Place._meta["index_specs"]
)
assert [{"fields": [("location.point", "2d")]}] == Place._meta["index_specs"]
Place.ensure_indexes()
info = Place._get_collection().index_information()
info = [value["key"] for key, value in iteritems(info)]
self.assertIn([("location.point", "2d")], info)
assert [("location.point", "2d")] in info
def test_explicit_geo2d_index_embedded(self):
"""Ensure that geo2d indexes work when created via meta[indexes]
@ -225,14 +221,14 @@ class TestIndexes(unittest.TestCase):
current = DictField(field=EmbeddedDocumentField("EmbeddedLocation"))
meta = {"allow_inheritance": True, "indexes": ["*current.location.point"]}
self.assertEqual(
[{"fields": [("current.location.point", "2d")]}], Place._meta["index_specs"]
)
assert [{"fields": [("current.location.point", "2d")]}] == Place._meta[
"index_specs"
]
Place.ensure_indexes()
info = Place._get_collection().index_information()
info = [value["key"] for key, value in iteritems(info)]
self.assertIn([("current.location.point", "2d")], info)
assert [("current.location.point", "2d")] in info
def test_explicit_geosphere_index(self):
"""Ensure that geosphere indexes work when created via meta[indexes]
@ -242,19 +238,19 @@ class TestIndexes(unittest.TestCase):
location = DictField()
meta = {"allow_inheritance": True, "indexes": ["(location.point"]}
self.assertEqual(
[{"fields": [("location.point", "2dsphere")]}], Place._meta["index_specs"]
)
assert [{"fields": [("location.point", "2dsphere")]}] == Place._meta[
"index_specs"
]
Place.ensure_indexes()
info = Place._get_collection().index_information()
info = [value["key"] for key, value in iteritems(info)]
self.assertIn([("location.point", "2dsphere")], info)
assert [("location.point", "2dsphere")] in info
def test_explicit_geohaystack_index(self):
"""Ensure that geohaystack indexes work when created via meta[indexes]
"""
raise SkipTest(
pytest.skip(
"GeoHaystack index creation is not supported for now"
"from meta, as it requires a bucketSize parameter."
)
@ -264,15 +260,14 @@ class TestIndexes(unittest.TestCase):
name = StringField()
meta = {"indexes": [(")location.point", "name")]}
self.assertEqual(
[{"fields": [("location.point", "geoHaystack"), ("name", 1)]}],
Place._meta["index_specs"],
)
assert [
{"fields": [("location.point", "geoHaystack"), ("name", 1)]}
] == Place._meta["index_specs"]
Place.ensure_indexes()
info = Place._get_collection().index_information()
info = [value["key"] for key, value in iteritems(info)]
self.assertIn([("location.point", "geoHaystack")], info)
assert [("location.point", "geoHaystack")] in info
def test_create_geohaystack_index(self):
"""Ensure that geohaystack indexes can be created
@ -285,7 +280,7 @@ class TestIndexes(unittest.TestCase):
Place.create_index({"fields": (")location.point", "name")}, bucketSize=10)
info = Place._get_collection().index_information()
info = [value["key"] for key, value in iteritems(info)]
self.assertIn([("location.point", "geoHaystack"), ("name", 1)], info)
assert [("location.point", "geoHaystack"), ("name", 1)] in info
def test_dictionary_indexes(self):
"""Ensure that indexes are used when meta[indexes] contains
@ -298,16 +293,15 @@ class TestIndexes(unittest.TestCase):
tags = ListField(StringField())
meta = {"indexes": [{"fields": ["-date"], "unique": True, "sparse": True}]}
self.assertEqual(
[{"fields": [("addDate", -1)], "unique": True, "sparse": True}],
BlogPost._meta["index_specs"],
)
assert [
{"fields": [("addDate", -1)], "unique": True, "sparse": True}
] == BlogPost._meta["index_specs"]
BlogPost.drop_collection()
info = BlogPost.objects._collection.index_information()
# _id, '-date'
self.assertEqual(len(info), 2)
assert len(info) == 2
# Indexes are lazy so use list() to perform query
list(BlogPost.objects)
@ -316,7 +310,7 @@ class TestIndexes(unittest.TestCase):
(value["key"], value.get("unique", False), value.get("sparse", False))
for key, value in iteritems(info)
]
self.assertIn(([("addDate", -1)], True, True), info)
assert ([("addDate", -1)], True, True) in info
BlogPost.drop_collection()
@ -338,11 +332,9 @@ class TestIndexes(unittest.TestCase):
Person(name="test", user_guid="123").save()
self.assertEqual(1, Person.objects.count())
assert 1 == Person.objects.count()
info = Person.objects._collection.index_information()
self.assertEqual(
sorted(info.keys()), ["_cls_1_name_1", "_cls_1_user_guid_1", "_id_"]
)
assert sorted(info.keys()) == ["_cls_1_name_1", "_cls_1_user_guid_1", "_id_"]
def test_disable_index_creation(self):
"""Tests setting auto_create_index to False on the connection will
@ -365,13 +357,13 @@ class TestIndexes(unittest.TestCase):
User(user_guid="123").save()
MongoUser(user_guid="123").save()
self.assertEqual(2, User.objects.count())
assert 2 == User.objects.count()
info = User.objects._collection.index_information()
self.assertEqual(list(info.keys()), ["_id_"])
assert list(info.keys()) == ["_id_"]
User.ensure_indexes()
info = User.objects._collection.index_information()
self.assertEqual(sorted(info.keys()), ["_cls_1_user_guid_1", "_id_"])
assert sorted(info.keys()) == ["_cls_1_user_guid_1", "_id_"]
def test_embedded_document_index(self):
"""Tests settings an index on an embedded document
@ -389,7 +381,7 @@ class TestIndexes(unittest.TestCase):
BlogPost.drop_collection()
info = BlogPost.objects._collection.index_information()
self.assertEqual(sorted(info.keys()), ["_id_", "date.yr_-1"])
assert sorted(info.keys()) == ["_id_", "date.yr_-1"]
def test_list_embedded_document_index(self):
"""Ensure list embedded documents can be indexed
@ -408,7 +400,7 @@ class TestIndexes(unittest.TestCase):
info = BlogPost.objects._collection.index_information()
# we don't use _cls in with list fields by default
self.assertEqual(sorted(info.keys()), ["_id_", "tags.tag_1"])
assert sorted(info.keys()) == ["_id_", "tags.tag_1"]
post1 = BlogPost(
title="Embedded Indexes tests in place",
@ -426,7 +418,7 @@ class TestIndexes(unittest.TestCase):
RecursiveDocument.ensure_indexes()
info = RecursiveDocument._get_collection().index_information()
self.assertEqual(sorted(info.keys()), ["_cls_1", "_id_"])
assert sorted(info.keys()) == ["_cls_1", "_id_"]
def test_covered_index(self):
"""Ensure that covered indexes can be used
@ -446,46 +438,45 @@ class TestIndexes(unittest.TestCase):
# Need to be explicit about covered indexes as mongoDB doesn't know if
# the documents returned might have more keys in that here.
query_plan = Test.objects(id=obj.id).exclude("a").explain()
self.assertEqual(
assert (
query_plan.get("queryPlanner")
.get("winningPlan")
.get("inputStage")
.get("stage"),
"IDHACK",
.get("stage")
== "IDHACK"
)
query_plan = Test.objects(id=obj.id).only("id").explain()
self.assertEqual(
assert (
query_plan.get("queryPlanner")
.get("winningPlan")
.get("inputStage")
.get("stage"),
"IDHACK",
.get("stage")
== "IDHACK"
)
query_plan = Test.objects(a=1).only("a").exclude("id").explain()
self.assertEqual(
assert (
query_plan.get("queryPlanner")
.get("winningPlan")
.get("inputStage")
.get("stage"),
"IXSCAN",
.get("stage")
== "IXSCAN"
)
self.assertEqual(
query_plan.get("queryPlanner").get("winningPlan").get("stage"), "PROJECTION"
assert (
query_plan.get("queryPlanner").get("winningPlan").get("stage")
== "PROJECTION"
)
query_plan = Test.objects(a=1).explain()
self.assertEqual(
assert (
query_plan.get("queryPlanner")
.get("winningPlan")
.get("inputStage")
.get("stage"),
"IXSCAN",
)
self.assertEqual(
query_plan.get("queryPlanner").get("winningPlan").get("stage"), "FETCH"
.get("stage")
== "IXSCAN"
)
assert query_plan.get("queryPlanner").get("winningPlan").get("stage") == "FETCH"
def test_index_on_id(self):
class BlogPost(Document):
@ -498,9 +489,7 @@ class TestIndexes(unittest.TestCase):
BlogPost.drop_collection()
indexes = BlogPost.objects._collection.index_information()
self.assertEqual(
indexes["categories_1__id_1"]["key"], [("categories", 1), ("_id", 1)]
)
assert indexes["categories_1__id_1"]["key"] == [("categories", 1), ("_id", 1)]
def test_hint(self):
TAGS_INDEX_NAME = "tags_1"
@ -516,25 +505,25 @@ class TestIndexes(unittest.TestCase):
BlogPost(tags=tags).save()
# Hinting by shape should work.
self.assertEqual(BlogPost.objects.hint([("tags", 1)]).count(), 10)
assert BlogPost.objects.hint([("tags", 1)]).count() == 10
# Hinting by index name should work.
self.assertEqual(BlogPost.objects.hint(TAGS_INDEX_NAME).count(), 10)
assert BlogPost.objects.hint(TAGS_INDEX_NAME).count() == 10
# Clearing the hint should work fine.
self.assertEqual(BlogPost.objects.hint().count(), 10)
self.assertEqual(BlogPost.objects.hint([("ZZ", 1)]).hint().count(), 10)
assert BlogPost.objects.hint().count() == 10
assert BlogPost.objects.hint([("ZZ", 1)]).hint().count() == 10
# Hinting on a non-existent index shape should fail.
with self.assertRaises(OperationFailure):
with pytest.raises(OperationFailure):
BlogPost.objects.hint([("ZZ", 1)]).count()
# Hinting on a non-existent index name should fail.
with self.assertRaises(OperationFailure):
with pytest.raises(OperationFailure):
BlogPost.objects.hint("Bad Name").count()
# Invalid shape argument (missing list brackets) should fail.
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
BlogPost.objects.hint(("tags", 1)).count()
def test_collation(self):
@ -555,23 +544,19 @@ class TestIndexes(unittest.TestCase):
BlogPost(name=name).save()
query_result = BlogPost.objects.collation(base).order_by("name")
self.assertEqual(
[x.name for x in query_result], sorted(names, key=lambda x: x.lower())
)
self.assertEqual(5, query_result.count())
assert [x.name for x in query_result] == sorted(names, key=lambda x: x.lower())
assert 5 == query_result.count()
query_result = BlogPost.objects.collation(Collation(**base)).order_by("name")
self.assertEqual(
[x.name for x in query_result], sorted(names, key=lambda x: x.lower())
)
self.assertEqual(5, query_result.count())
assert [x.name for x in query_result] == sorted(names, key=lambda x: x.lower())
assert 5 == query_result.count()
incorrect_collation = {"arndom": "wrdo"}
with self.assertRaises(OperationFailure):
with pytest.raises(OperationFailure):
BlogPost.objects.collation(incorrect_collation).count()
query_result = BlogPost.objects.collation({}).order_by("name")
self.assertEqual([x.name for x in query_result], sorted(names))
assert [x.name for x in query_result] == sorted(names)
def test_unique(self):
"""Ensure that uniqueness constraints are applied to fields.
@ -588,11 +573,14 @@ class TestIndexes(unittest.TestCase):
# Two posts with the same slug is not allowed
post2 = BlogPost(title="test2", slug="test")
self.assertRaises(NotUniqueError, post2.save)
self.assertRaises(NotUniqueError, BlogPost.objects.insert, post2)
with pytest.raises(NotUniqueError):
post2.save()
with pytest.raises(NotUniqueError):
BlogPost.objects.insert(post2)
# Ensure backwards compatibility for errors
self.assertRaises(OperationError, post2.save)
with pytest.raises(OperationError):
post2.save()
def test_primary_key_unique_not_working(self):
"""Relates to #1445"""
@ -602,23 +590,21 @@ class TestIndexes(unittest.TestCase):
Blog.drop_collection()
with self.assertRaises(OperationFailure) as ctx_err:
with pytest.raises(OperationFailure) as exc_info:
Blog(id="garbage").save()
# One of the errors below should happen. Which one depends on the
# PyMongo version and dict order.
err_msg = str(ctx_err.exception)
self.assertTrue(
any(
[
"The field 'unique' is not valid for an _id index specification"
in err_msg,
"The field 'background' is not valid for an _id index specification"
in err_msg,
"The field 'sparse' is not valid for an _id index specification"
in err_msg,
]
)
err_msg = str(exc_info.value)
assert any(
[
"The field 'unique' is not valid for an _id index specification"
in err_msg,
"The field 'background' is not valid for an _id index specification"
in err_msg,
"The field 'sparse' is not valid for an _id index specification"
in err_msg,
]
)
def test_unique_with(self):
@ -644,7 +630,8 @@ class TestIndexes(unittest.TestCase):
# Now there will be two docs with the same slug and the same day: fail
post3 = BlogPost(title="test3", date=Date(year=2010), slug="test")
self.assertRaises(OperationError, post3.save)
with pytest.raises(OperationError):
post3.save()
def test_unique_embedded_document(self):
"""Ensure that uniqueness constraints are applied to fields on embedded documents.
@ -669,7 +656,8 @@ class TestIndexes(unittest.TestCase):
# Now there will be two docs with the same sub.slug
post3 = BlogPost(title="test3", sub=SubDocument(year=2010, slug="test"))
self.assertRaises(NotUniqueError, post3.save)
with pytest.raises(NotUniqueError):
post3.save()
def test_unique_embedded_document_in_list(self):
"""
@ -699,7 +687,8 @@ class TestIndexes(unittest.TestCase):
post2 = BlogPost(title="test2", subs=[SubDocument(year=2014, slug="conflict")])
self.assertRaises(NotUniqueError, post2.save)
with pytest.raises(NotUniqueError):
post2.save()
def test_unique_embedded_document_in_sorted_list(self):
"""
@ -729,12 +718,13 @@ class TestIndexes(unittest.TestCase):
# confirm that the unique index is created
indexes = BlogPost._get_collection().index_information()
self.assertIn("subs.slug_1", indexes)
self.assertTrue(indexes["subs.slug_1"]["unique"])
assert "subs.slug_1" in indexes
assert indexes["subs.slug_1"]["unique"]
post2 = BlogPost(title="test2", subs=[SubDocument(year=2014, slug="conflict")])
self.assertRaises(NotUniqueError, post2.save)
with pytest.raises(NotUniqueError):
post2.save()
def test_unique_embedded_document_in_embedded_document_list(self):
"""
@ -764,12 +754,13 @@ class TestIndexes(unittest.TestCase):
# confirm that the unique index is created
indexes = BlogPost._get_collection().index_information()
self.assertIn("subs.slug_1", indexes)
self.assertTrue(indexes["subs.slug_1"]["unique"])
assert "subs.slug_1" in indexes
assert indexes["subs.slug_1"]["unique"]
post2 = BlogPost(title="test2", subs=[SubDocument(year=2014, slug="conflict")])
self.assertRaises(NotUniqueError, post2.save)
with pytest.raises(NotUniqueError):
post2.save()
def test_unique_with_embedded_document_and_embedded_unique(self):
"""Ensure that uniqueness constraints are applied to fields on
@ -795,11 +786,13 @@ class TestIndexes(unittest.TestCase):
# Now there will be two docs with the same sub.slug
post3 = BlogPost(title="test3", sub=SubDocument(year=2010, slug="test"))
self.assertRaises(NotUniqueError, post3.save)
with pytest.raises(NotUniqueError):
post3.save()
# Now there will be two docs with the same title and year
post3 = BlogPost(title="test1", sub=SubDocument(year=2009, slug="test-1"))
self.assertRaises(NotUniqueError, post3.save)
with pytest.raises(NotUniqueError):
post3.save()
def test_ttl_indexes(self):
class Log(Document):
@ -811,7 +804,7 @@ class TestIndexes(unittest.TestCase):
# Indexes are lazy so use list() to perform query
list(Log.objects)
info = Log.objects._collection.index_information()
self.assertEqual(3600, info["created_1"]["expireAfterSeconds"])
assert 3600 == info["created_1"]["expireAfterSeconds"]
def test_index_drop_dups_silently_ignored(self):
class Customer(Document):
@ -839,14 +832,14 @@ class TestIndexes(unittest.TestCase):
cust.save()
cust_dupe = Customer(cust_id=1)
with self.assertRaises(NotUniqueError):
with pytest.raises(NotUniqueError):
cust_dupe.save()
cust = Customer(cust_id=2)
cust.save()
# duplicate key on update
with self.assertRaises(NotUniqueError):
with pytest.raises(NotUniqueError):
cust.cust_id = 1
cust.save()
@ -867,8 +860,8 @@ class TestIndexes(unittest.TestCase):
user = User(name="huangz", password="secret2")
user.save()
self.assertEqual(User.objects.count(), 1)
self.assertEqual(User.objects.get().password, "secret2")
assert User.objects.count() == 1
assert User.objects.get().password == "secret2"
def test_unique_and_primary_create(self):
"""Create a new record with a duplicate primary key
@ -882,11 +875,11 @@ class TestIndexes(unittest.TestCase):
User.drop_collection()
User.objects.create(name="huangz", password="secret")
with self.assertRaises(NotUniqueError):
with pytest.raises(NotUniqueError):
User.objects.create(name="huangz", password="secret2")
self.assertEqual(User.objects.count(), 1)
self.assertEqual(User.objects.get().password, "secret")
assert User.objects.count() == 1
assert User.objects.get().password == "secret"
def test_index_with_pk(self):
"""Ensure you can use `pk` as part of a query"""
@ -910,7 +903,7 @@ class TestIndexes(unittest.TestCase):
info = BlogPost.objects._collection.index_information()
info = [value["key"] for key, value in iteritems(info)]
index_item = [("_id", 1), ("comments.comment_id", 1)]
self.assertIn(index_item, info)
assert index_item in info
def test_compound_key_embedded(self):
class CompoundKey(EmbeddedDocument):
@ -924,10 +917,8 @@ class TestIndexes(unittest.TestCase):
my_key = CompoundKey(name="n", term="ok")
report = ReportEmbedded(text="OK", key=my_key).save()
self.assertEqual(
{"text": "OK", "_id": {"term": "ok", "name": "n"}}, report.to_mongo()
)
self.assertEqual(report, ReportEmbedded.objects.get(pk=my_key))
assert {"text": "OK", "_id": {"term": "ok", "name": "n"}} == report.to_mongo()
assert report == ReportEmbedded.objects.get(pk=my_key)
def test_compound_key_dictfield(self):
class ReportDictField(Document):
@ -937,15 +928,13 @@ class TestIndexes(unittest.TestCase):
my_key = {"name": "n", "term": "ok"}
report = ReportDictField(text="OK", key=my_key).save()
self.assertEqual(
{"text": "OK", "_id": {"term": "ok", "name": "n"}}, report.to_mongo()
)
assert {"text": "OK", "_id": {"term": "ok", "name": "n"}} == report.to_mongo()
# We can't directly call ReportDictField.objects.get(pk=my_key),
# because dicts are unordered, and if the order in MongoDB is
# different than the one in `my_key`, this test will fail.
self.assertEqual(report, ReportDictField.objects.get(pk__name=my_key["name"]))
self.assertEqual(report, ReportDictField.objects.get(pk__term=my_key["term"]))
assert report == ReportDictField.objects.get(pk__name=my_key["name"])
assert report == ReportDictField.objects.get(pk__term=my_key["term"])
def test_string_indexes(self):
class MyDoc(Document):
@ -954,8 +943,8 @@ class TestIndexes(unittest.TestCase):
info = MyDoc.objects._collection.index_information()
info = [value["key"] for key, value in iteritems(info)]
self.assertIn([("provider_ids.foo", 1)], info)
self.assertIn([("provider_ids.bar", 1)], info)
assert [("provider_ids.foo", 1)] in info
assert [("provider_ids.bar", 1)] in info
def test_sparse_compound_indexes(self):
class MyDoc(Document):
@ -967,11 +956,10 @@ class TestIndexes(unittest.TestCase):
}
info = MyDoc.objects._collection.index_information()
self.assertEqual(
[("provider_ids.foo", 1), ("provider_ids.bar", 1)],
info["provider_ids.foo_1_provider_ids.bar_1"]["key"],
)
self.assertTrue(info["provider_ids.foo_1_provider_ids.bar_1"]["sparse"])
assert [("provider_ids.foo", 1), ("provider_ids.bar", 1)] == info[
"provider_ids.foo_1_provider_ids.bar_1"
]["key"]
assert info["provider_ids.foo_1_provider_ids.bar_1"]["sparse"]
def test_text_indexes(self):
class Book(Document):
@ -979,9 +967,9 @@ class TestIndexes(unittest.TestCase):
meta = {"indexes": ["$title"]}
indexes = Book.objects._collection.index_information()
self.assertIn("title_text", indexes)
assert "title_text" in indexes
key = indexes["title_text"]["key"]
self.assertIn(("_fts", "text"), key)
assert ("_fts", "text") in key
def test_hashed_indexes(self):
class Book(Document):
@ -989,8 +977,8 @@ class TestIndexes(unittest.TestCase):
meta = {"indexes": ["#ref_id"]}
indexes = Book.objects._collection.index_information()
self.assertIn("ref_id_hashed", indexes)
self.assertIn(("ref_id", "hashed"), indexes["ref_id_hashed"]["key"])
assert "ref_id_hashed" in indexes
assert ("ref_id", "hashed") in indexes["ref_id_hashed"]["key"]
def test_indexes_after_database_drop(self):
"""
@ -1027,7 +1015,8 @@ class TestIndexes(unittest.TestCase):
# Create Post #2
post2 = BlogPost(title="test2", slug="test")
self.assertRaises(NotUniqueError, post2.save)
with pytest.raises(NotUniqueError):
post2.save()
finally:
# Drop the temporary database at the end
connection.drop_database("tempdatabase")
@ -1074,15 +1063,12 @@ class TestIndexes(unittest.TestCase):
"dropDups"
] # drop the index dropDups - it is deprecated in MongoDB 3+
self.assertEqual(
index_info,
{
"txt_1": {"key": [("txt", 1)], "background": False},
"_id_": {"key": [("_id", 1)]},
"txt2_1": {"key": [("txt2", 1)], "background": False},
"_cls_1": {"key": [("_cls", 1)], "background": False},
},
)
assert index_info == {
"txt_1": {"key": [("txt", 1)], "background": False},
"_id_": {"key": [("_id", 1)]},
"txt2_1": {"key": [("txt2", 1)], "background": False},
"_cls_1": {"key": [("_cls", 1)], "background": False},
}
def test_compound_index_underscore_cls_not_overwritten(self):
"""
@ -1105,7 +1091,7 @@ class TestIndexes(unittest.TestCase):
TestDoc.ensure_indexes()
index_info = TestDoc._get_collection().index_information()
self.assertIn("shard_1_1__cls_1_txt_1_1", index_info)
assert "shard_1_1__cls_1_txt_1_1" in index_info
if __name__ == "__main__":

View File

@ -2,6 +2,7 @@
import unittest
import warnings
import pytest
from six import iteritems
from mongoengine import (
@ -37,12 +38,12 @@ class TestInheritance(MongoDBTestCase):
meta = {"allow_inheritance": True}
test_doc = DataDoc(name="test", embed=EmbedData(data="data"))
self.assertEqual(test_doc._cls, "DataDoc")
self.assertEqual(test_doc.embed._cls, "EmbedData")
assert test_doc._cls == "DataDoc"
assert test_doc.embed._cls == "EmbedData"
test_doc.save()
saved_doc = DataDoc.objects.with_id(test_doc.id)
self.assertEqual(test_doc._cls, saved_doc._cls)
self.assertEqual(test_doc.embed._cls, saved_doc.embed._cls)
assert test_doc._cls == saved_doc._cls
assert test_doc.embed._cls == saved_doc.embed._cls
test_doc.delete()
def test_superclasses(self):
@ -67,12 +68,12 @@ class TestInheritance(MongoDBTestCase):
class Human(Mammal):
pass
self.assertEqual(Animal._superclasses, ())
self.assertEqual(Fish._superclasses, ("Animal",))
self.assertEqual(Guppy._superclasses, ("Animal", "Animal.Fish"))
self.assertEqual(Mammal._superclasses, ("Animal",))
self.assertEqual(Dog._superclasses, ("Animal", "Animal.Mammal"))
self.assertEqual(Human._superclasses, ("Animal", "Animal.Mammal"))
assert Animal._superclasses == ()
assert Fish._superclasses == ("Animal",)
assert Guppy._superclasses == ("Animal", "Animal.Fish")
assert Mammal._superclasses == ("Animal",)
assert Dog._superclasses == ("Animal", "Animal.Mammal")
assert Human._superclasses == ("Animal", "Animal.Mammal")
def test_external_superclasses(self):
"""Ensure that the correct list of super classes is assembled when
@ -97,18 +98,12 @@ class TestInheritance(MongoDBTestCase):
class Human(Mammal):
pass
self.assertEqual(Animal._superclasses, ("Base",))
self.assertEqual(Fish._superclasses, ("Base", "Base.Animal"))
self.assertEqual(
Guppy._superclasses, ("Base", "Base.Animal", "Base.Animal.Fish")
)
self.assertEqual(Mammal._superclasses, ("Base", "Base.Animal"))
self.assertEqual(
Dog._superclasses, ("Base", "Base.Animal", "Base.Animal.Mammal")
)
self.assertEqual(
Human._superclasses, ("Base", "Base.Animal", "Base.Animal.Mammal")
)
assert Animal._superclasses == ("Base",)
assert Fish._superclasses == ("Base", "Base.Animal")
assert Guppy._superclasses == ("Base", "Base.Animal", "Base.Animal.Fish")
assert Mammal._superclasses == ("Base", "Base.Animal")
assert Dog._superclasses == ("Base", "Base.Animal", "Base.Animal.Mammal")
assert Human._superclasses == ("Base", "Base.Animal", "Base.Animal.Mammal")
def test_subclasses(self):
"""Ensure that the correct list of _subclasses (subclasses) is
@ -133,24 +128,22 @@ class TestInheritance(MongoDBTestCase):
class Human(Mammal):
pass
self.assertEqual(
Animal._subclasses,
(
"Animal",
"Animal.Fish",
"Animal.Fish.Guppy",
"Animal.Mammal",
"Animal.Mammal.Dog",
"Animal.Mammal.Human",
),
assert Animal._subclasses == (
"Animal",
"Animal.Fish",
"Animal.Fish.Guppy",
"Animal.Mammal",
"Animal.Mammal.Dog",
"Animal.Mammal.Human",
)
self.assertEqual(Fish._subclasses, ("Animal.Fish", "Animal.Fish.Guppy"))
self.assertEqual(Guppy._subclasses, ("Animal.Fish.Guppy",))
self.assertEqual(
Mammal._subclasses,
("Animal.Mammal", "Animal.Mammal.Dog", "Animal.Mammal.Human"),
assert Fish._subclasses == ("Animal.Fish", "Animal.Fish.Guppy")
assert Guppy._subclasses == ("Animal.Fish.Guppy",)
assert Mammal._subclasses == (
"Animal.Mammal",
"Animal.Mammal.Dog",
"Animal.Mammal.Human",
)
self.assertEqual(Human._subclasses, ("Animal.Mammal.Human",))
assert Human._subclasses == ("Animal.Mammal.Human",)
def test_external_subclasses(self):
"""Ensure that the correct list of _subclasses (subclasses) is
@ -175,30 +168,22 @@ class TestInheritance(MongoDBTestCase):
class Human(Mammal):
pass
self.assertEqual(
Animal._subclasses,
(
"Base.Animal",
"Base.Animal.Fish",
"Base.Animal.Fish.Guppy",
"Base.Animal.Mammal",
"Base.Animal.Mammal.Dog",
"Base.Animal.Mammal.Human",
),
assert Animal._subclasses == (
"Base.Animal",
"Base.Animal.Fish",
"Base.Animal.Fish.Guppy",
"Base.Animal.Mammal",
"Base.Animal.Mammal.Dog",
"Base.Animal.Mammal.Human",
)
self.assertEqual(
Fish._subclasses, ("Base.Animal.Fish", "Base.Animal.Fish.Guppy")
assert Fish._subclasses == ("Base.Animal.Fish", "Base.Animal.Fish.Guppy")
assert Guppy._subclasses == ("Base.Animal.Fish.Guppy",)
assert Mammal._subclasses == (
"Base.Animal.Mammal",
"Base.Animal.Mammal.Dog",
"Base.Animal.Mammal.Human",
)
self.assertEqual(Guppy._subclasses, ("Base.Animal.Fish.Guppy",))
self.assertEqual(
Mammal._subclasses,
(
"Base.Animal.Mammal",
"Base.Animal.Mammal.Dog",
"Base.Animal.Mammal.Human",
),
)
self.assertEqual(Human._subclasses, ("Base.Animal.Mammal.Human",))
assert Human._subclasses == ("Base.Animal.Mammal.Human",)
def test_dynamic_declarations(self):
"""Test that declaring an extra class updates meta data"""
@ -206,33 +191,31 @@ class TestInheritance(MongoDBTestCase):
class Animal(Document):
meta = {"allow_inheritance": True}
self.assertEqual(Animal._superclasses, ())
self.assertEqual(Animal._subclasses, ("Animal",))
assert Animal._superclasses == ()
assert Animal._subclasses == ("Animal",)
# Test dynamically adding a class changes the meta data
class Fish(Animal):
pass
self.assertEqual(Animal._superclasses, ())
self.assertEqual(Animal._subclasses, ("Animal", "Animal.Fish"))
assert Animal._superclasses == ()
assert Animal._subclasses == ("Animal", "Animal.Fish")
self.assertEqual(Fish._superclasses, ("Animal",))
self.assertEqual(Fish._subclasses, ("Animal.Fish",))
assert Fish._superclasses == ("Animal",)
assert Fish._subclasses == ("Animal.Fish",)
# Test dynamically adding an inherited class changes the meta data
class Pike(Fish):
pass
self.assertEqual(Animal._superclasses, ())
self.assertEqual(
Animal._subclasses, ("Animal", "Animal.Fish", "Animal.Fish.Pike")
)
assert Animal._superclasses == ()
assert Animal._subclasses == ("Animal", "Animal.Fish", "Animal.Fish.Pike")
self.assertEqual(Fish._superclasses, ("Animal",))
self.assertEqual(Fish._subclasses, ("Animal.Fish", "Animal.Fish.Pike"))
assert Fish._superclasses == ("Animal",)
assert Fish._subclasses == ("Animal.Fish", "Animal.Fish.Pike")
self.assertEqual(Pike._superclasses, ("Animal", "Animal.Fish"))
self.assertEqual(Pike._subclasses, ("Animal.Fish.Pike",))
assert Pike._superclasses == ("Animal", "Animal.Fish")
assert Pike._subclasses == ("Animal.Fish.Pike",)
def test_inheritance_meta_data(self):
"""Ensure that document may inherit fields from a superclass document.
@ -247,10 +230,10 @@ class TestInheritance(MongoDBTestCase):
class Employee(Person):
salary = IntField()
self.assertEqual(
["_cls", "age", "id", "name", "salary"], sorted(Employee._fields.keys())
assert ["_cls", "age", "id", "name", "salary"] == sorted(
Employee._fields.keys()
)
self.assertEqual(Employee._get_collection_name(), Person._get_collection_name())
assert Employee._get_collection_name() == Person._get_collection_name()
def test_inheritance_to_mongo_keys(self):
"""Ensure that document may inherit fields from a superclass document.
@ -265,17 +248,17 @@ class TestInheritance(MongoDBTestCase):
class Employee(Person):
salary = IntField()
self.assertEqual(
["_cls", "age", "id", "name", "salary"], sorted(Employee._fields.keys())
assert ["_cls", "age", "id", "name", "salary"] == sorted(
Employee._fields.keys()
)
self.assertEqual(
Person(name="Bob", age=35).to_mongo().keys(), ["_cls", "name", "age"]
)
self.assertEqual(
Employee(name="Bob", age=35, salary=0).to_mongo().keys(),
["_cls", "name", "age", "salary"],
)
self.assertEqual(Employee._get_collection_name(), Person._get_collection_name())
assert Person(name="Bob", age=35).to_mongo().keys() == ["_cls", "name", "age"]
assert Employee(name="Bob", age=35, salary=0).to_mongo().keys() == [
"_cls",
"name",
"age",
"salary",
]
assert Employee._get_collection_name() == Person._get_collection_name()
def test_indexes_and_multiple_inheritance(self):
""" Ensure that all of the indexes are created for a document with
@ -301,13 +284,10 @@ class TestInheritance(MongoDBTestCase):
C.ensure_indexes()
self.assertEqual(
sorted(
[idx["key"] for idx in C._get_collection().index_information().values()]
),
sorted(
[[(u"_cls", 1), (u"b", 1)], [(u"_id", 1)], [(u"_cls", 1), (u"a", 1)]]
),
assert sorted(
[idx["key"] for idx in C._get_collection().index_information().values()]
) == sorted(
[[(u"_cls", 1), (u"b", 1)], [(u"_id", 1)], [(u"_cls", 1), (u"a", 1)]]
)
def test_polymorphic_queries(self):
@ -338,13 +318,13 @@ class TestInheritance(MongoDBTestCase):
Human().save()
classes = [obj.__class__ for obj in Animal.objects]
self.assertEqual(classes, [Animal, Fish, Mammal, Dog, Human])
assert classes == [Animal, Fish, Mammal, Dog, Human]
classes = [obj.__class__ for obj in Mammal.objects]
self.assertEqual(classes, [Mammal, Dog, Human])
assert classes == [Mammal, Dog, Human]
classes = [obj.__class__ for obj in Human.objects]
self.assertEqual(classes, [Human])
assert classes == [Human]
def test_allow_inheritance(self):
"""Ensure that inheritance is disabled by default on simple
@ -355,20 +335,18 @@ class TestInheritance(MongoDBTestCase):
name = StringField()
# can't inherit because Animal didn't explicitly allow inheritance
with self.assertRaises(ValueError) as cm:
with pytest.raises(ValueError, match="Document Animal may not be subclassed"):
class Dog(Animal):
pass
self.assertIn("Document Animal may not be subclassed", str(cm.exception))
# Check that _cls etc aren't present on simple documents
dog = Animal(name="dog").save()
self.assertEqual(dog.to_mongo().keys(), ["_id", "name"])
assert dog.to_mongo().keys() == ["_id", "name"]
collection = self.db[Animal._get_collection_name()]
obj = collection.find_one()
self.assertNotIn("_cls", obj)
assert "_cls" not in obj
def test_cant_turn_off_inheritance_on_subclass(self):
"""Ensure if inheritance is on in a subclass you cant turn it off.
@ -378,14 +356,14 @@ class TestInheritance(MongoDBTestCase):
name = StringField()
meta = {"allow_inheritance": True}
with self.assertRaises(ValueError) as cm:
with pytest.raises(ValueError) as exc_info:
class Mammal(Animal):
meta = {"allow_inheritance": False}
self.assertEqual(
str(cm.exception),
'Only direct subclasses of Document may set "allow_inheritance" to False',
assert (
str(exc_info.value)
== 'Only direct subclasses of Document may set "allow_inheritance" to False'
)
def test_allow_inheritance_abstract_document(self):
@ -399,14 +377,14 @@ class TestInheritance(MongoDBTestCase):
class Animal(FinalDocument):
name = StringField()
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
class Mammal(Animal):
pass
# Check that _cls isn't present in simple documents
doc = Animal(name="dog")
self.assertNotIn("_cls", doc.to_mongo())
assert "_cls" not in doc.to_mongo()
def test_using_abstract_class_in_reference_field(self):
# Ensures no regression of #1920
@ -452,10 +430,10 @@ class TestInheritance(MongoDBTestCase):
name = StringField()
berlin = EuropeanCity(name="Berlin", continent="Europe")
self.assertEqual(len(berlin._db_field_map), len(berlin._fields_ordered))
self.assertEqual(len(berlin._reverse_db_field_map), len(berlin._fields_ordered))
self.assertEqual(len(berlin._fields_ordered), 3)
self.assertEqual(berlin._fields_ordered[0], "id")
assert len(berlin._db_field_map) == len(berlin._fields_ordered)
assert len(berlin._reverse_db_field_map) == len(berlin._fields_ordered)
assert len(berlin._fields_ordered) == 3
assert berlin._fields_ordered[0] == "id"
def test_auto_id_not_set_if_specific_in_parent_class(self):
class City(Document):
@ -467,10 +445,10 @@ class TestInheritance(MongoDBTestCase):
name = StringField()
berlin = EuropeanCity(name="Berlin", continent="Europe")
self.assertEqual(len(berlin._db_field_map), len(berlin._fields_ordered))
self.assertEqual(len(berlin._reverse_db_field_map), len(berlin._fields_ordered))
self.assertEqual(len(berlin._fields_ordered), 3)
self.assertEqual(berlin._fields_ordered[0], "city_id")
assert len(berlin._db_field_map) == len(berlin._fields_ordered)
assert len(berlin._reverse_db_field_map) == len(berlin._fields_ordered)
assert len(berlin._fields_ordered) == 3
assert berlin._fields_ordered[0] == "city_id"
def test_auto_id_vs_non_pk_id_field(self):
class City(Document):
@ -482,12 +460,12 @@ class TestInheritance(MongoDBTestCase):
name = StringField()
berlin = EuropeanCity(name="Berlin", continent="Europe")
self.assertEqual(len(berlin._db_field_map), len(berlin._fields_ordered))
self.assertEqual(len(berlin._reverse_db_field_map), len(berlin._fields_ordered))
self.assertEqual(len(berlin._fields_ordered), 4)
self.assertEqual(berlin._fields_ordered[0], "auto_id_0")
assert len(berlin._db_field_map) == len(berlin._fields_ordered)
assert len(berlin._reverse_db_field_map) == len(berlin._fields_ordered)
assert len(berlin._fields_ordered) == 4
assert berlin._fields_ordered[0] == "auto_id_0"
berlin.save()
self.assertEqual(berlin.pk, berlin.auto_id_0)
assert berlin.pk == berlin.auto_id_0
def test_abstract_document_creation_does_not_fail(self):
class City(Document):
@ -495,9 +473,9 @@ class TestInheritance(MongoDBTestCase):
meta = {"abstract": True, "allow_inheritance": False}
city = City(continent="asia")
self.assertEqual(None, city.pk)
assert city.pk is None
# TODO: expected error? Shouldn't we create a new error type?
with self.assertRaises(KeyError):
with pytest.raises(KeyError):
setattr(city, "pk", 1)
def test_allow_inheritance_embedded_document(self):
@ -506,20 +484,20 @@ class TestInheritance(MongoDBTestCase):
class Comment(EmbeddedDocument):
content = StringField()
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
class SpecialComment(Comment):
pass
doc = Comment(content="test")
self.assertNotIn("_cls", doc.to_mongo())
assert "_cls" not in doc.to_mongo()
class Comment(EmbeddedDocument):
content = StringField()
meta = {"allow_inheritance": True}
doc = Comment(content="test")
self.assertIn("_cls", doc.to_mongo())
assert "_cls" in doc.to_mongo()
def test_document_inheritance(self):
"""Ensure mutliple inheritance of abstract documents
@ -537,7 +515,7 @@ class TestInheritance(MongoDBTestCase):
pass
except Exception:
self.assertTrue(False, "Couldn't create MyDocument class")
assert False, "Couldn't create MyDocument class"
def test_abstract_documents(self):
"""Ensure that a document superclass can be marked as abstract
@ -574,20 +552,20 @@ class TestInheritance(MongoDBTestCase):
for k, v in iteritems(defaults):
for cls in [Animal, Fish, Guppy]:
self.assertEqual(cls._meta[k], v)
assert cls._meta[k] == v
self.assertNotIn("collection", Animal._meta)
self.assertNotIn("collection", Mammal._meta)
assert "collection" not in Animal._meta
assert "collection" not in Mammal._meta
self.assertEqual(Animal._get_collection_name(), None)
self.assertEqual(Mammal._get_collection_name(), None)
assert Animal._get_collection_name() is None
assert Mammal._get_collection_name() is None
self.assertEqual(Fish._get_collection_name(), "fish")
self.assertEqual(Guppy._get_collection_name(), "fish")
self.assertEqual(Human._get_collection_name(), "human")
assert Fish._get_collection_name() == "fish"
assert Guppy._get_collection_name() == "fish"
assert Human._get_collection_name() == "human"
# ensure that a subclass of a non-abstract class can't be abstract
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
class EvilHuman(Human):
evil = BooleanField(default=True)
@ -601,7 +579,7 @@ class TestInheritance(MongoDBTestCase):
class B(A):
pass
self.assertFalse(B._meta["abstract"])
assert not B._meta["abstract"]
def test_inherited_collections(self):
"""Ensure that subclassed documents don't override parents'
@ -647,8 +625,8 @@ class TestInheritance(MongoDBTestCase):
real_person = Drinker(drink=beer)
real_person.save()
self.assertEqual(Drinker.objects[0].drink.name, red_bull.name)
self.assertEqual(Drinker.objects[1].drink.name, beer.name)
assert Drinker.objects[0].drink.name == red_bull.name
assert Drinker.objects[1].drink.name == beer.name
if __name__ == "__main__":

File diff suppressed because it is too large Load Diff

View File

@ -32,7 +32,7 @@ class TestJson(MongoDBTestCase):
expected_json = """{"embedded":{"string":"Inner Hello"},"string":"Hello"}"""
self.assertEqual(doc_json, expected_json)
assert doc_json == expected_json
def test_json_simple(self):
class Embedded(EmbeddedDocument):
@ -52,9 +52,9 @@ class TestJson(MongoDBTestCase):
doc_json = doc.to_json(sort_keys=True, separators=(",", ":"))
expected_json = """{"embedded_field":{"string":"Hi"},"string":"Hi"}"""
self.assertEqual(doc_json, expected_json)
assert doc_json == expected_json
self.assertEqual(doc, Doc.from_json(doc.to_json()))
assert doc == Doc.from_json(doc.to_json())
def test_json_complex(self):
class EmbeddedDoc(EmbeddedDocument):
@ -99,7 +99,7 @@ class TestJson(MongoDBTestCase):
return json.loads(self.to_json()) == json.loads(other.to_json())
doc = Doc()
self.assertEqual(doc, Doc.from_json(doc.to_json()))
assert doc == Doc.from_json(doc.to_json())
if __name__ == "__main__":

View File

@ -2,6 +2,8 @@
import unittest
from datetime import datetime
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -11,12 +13,12 @@ class TestValidatorError(MongoDBTestCase):
"""Ensure a ValidationError handles error to_dict correctly.
"""
error = ValidationError("root")
self.assertEqual(error.to_dict(), {})
assert error.to_dict() == {}
# 1st level error schema
error.errors = {"1st": ValidationError("bad 1st")}
self.assertIn("1st", error.to_dict())
self.assertEqual(error.to_dict()["1st"], "bad 1st")
assert "1st" in error.to_dict()
assert error.to_dict()["1st"] == "bad 1st"
# 2nd level error schema
error.errors = {
@ -24,10 +26,10 @@ class TestValidatorError(MongoDBTestCase):
"bad 1st", errors={"2nd": ValidationError("bad 2nd")}
)
}
self.assertIn("1st", error.to_dict())
self.assertIsInstance(error.to_dict()["1st"], dict)
self.assertIn("2nd", error.to_dict()["1st"])
self.assertEqual(error.to_dict()["1st"]["2nd"], "bad 2nd")
assert "1st" in error.to_dict()
assert isinstance(error.to_dict()["1st"], dict)
assert "2nd" in error.to_dict()["1st"]
assert error.to_dict()["1st"]["2nd"] == "bad 2nd"
# moar levels
error.errors = {
@ -45,13 +47,13 @@ class TestValidatorError(MongoDBTestCase):
},
)
}
self.assertIn("1st", error.to_dict())
self.assertIn("2nd", error.to_dict()["1st"])
self.assertIn("3rd", error.to_dict()["1st"]["2nd"])
self.assertIn("4th", error.to_dict()["1st"]["2nd"]["3rd"])
self.assertEqual(error.to_dict()["1st"]["2nd"]["3rd"]["4th"], "Inception")
assert "1st" in error.to_dict()
assert "2nd" in error.to_dict()["1st"]
assert "3rd" in error.to_dict()["1st"]["2nd"]
assert "4th" in error.to_dict()["1st"]["2nd"]["3rd"]
assert error.to_dict()["1st"]["2nd"]["3rd"]["4th"] == "Inception"
self.assertEqual(error.message, "root(2nd.3rd.4th.Inception: ['1st'])")
assert error.message == "root(2nd.3rd.4th.Inception: ['1st'])"
def test_model_validation(self):
class User(Document):
@ -61,19 +63,19 @@ class TestValidatorError(MongoDBTestCase):
try:
User().validate()
except ValidationError as e:
self.assertIn("User:None", e.message)
self.assertEqual(
e.to_dict(),
{"username": "Field is required", "name": "Field is required"},
)
assert "User:None" in e.message
assert e.to_dict() == {
"username": "Field is required",
"name": "Field is required",
}
user = User(username="RossC0", name="Ross").save()
user.name = None
try:
user.save()
except ValidationError as e:
self.assertIn("User:RossC0", e.message)
self.assertEqual(e.to_dict(), {"name": "Field is required"})
assert "User:RossC0" in e.message
assert e.to_dict() == {"name": "Field is required"}
def test_fields_rewrite(self):
class BasePerson(Document):
@ -85,7 +87,8 @@ class TestValidatorError(MongoDBTestCase):
name = StringField(required=True)
p = Person(age=15)
self.assertRaises(ValidationError, p.validate)
with pytest.raises(ValidationError):
p.validate()
def test_embedded_document_validation(self):
"""Ensure that embedded documents may be validated.
@ -96,17 +99,19 @@ class TestValidatorError(MongoDBTestCase):
content = StringField(required=True)
comment = Comment()
self.assertRaises(ValidationError, comment.validate)
with pytest.raises(ValidationError):
comment.validate()
comment.content = "test"
comment.validate()
comment.date = 4
self.assertRaises(ValidationError, comment.validate)
with pytest.raises(ValidationError):
comment.validate()
comment.date = datetime.now()
comment.validate()
self.assertEqual(comment._instance, None)
assert comment._instance is None
def test_embedded_db_field_validate(self):
class SubDoc(EmbeddedDocument):
@ -119,10 +124,8 @@ class TestValidatorError(MongoDBTestCase):
try:
Doc(id="bad").validate()
except ValidationError as e:
self.assertIn("SubDoc:None", e.message)
self.assertEqual(
e.to_dict(), {"e": {"val": "OK could not be converted to int"}}
)
assert "SubDoc:None" in e.message
assert e.to_dict() == {"e": {"val": "OK could not be converted to int"}}
Doc.drop_collection()
@ -130,18 +133,16 @@ class TestValidatorError(MongoDBTestCase):
doc = Doc.objects.first()
keys = doc._data.keys()
self.assertEqual(2, len(keys))
self.assertIn("e", keys)
self.assertIn("id", keys)
assert 2 == len(keys)
assert "e" in keys
assert "id" in keys
doc.e.val = "OK"
try:
doc.save()
except ValidationError as e:
self.assertIn("Doc:test", e.message)
self.assertEqual(
e.to_dict(), {"e": {"val": "OK could not be converted to int"}}
)
assert "Doc:test" in e.message
assert e.to_dict() == {"e": {"val": "OK could not be converted to int"}}
def test_embedded_weakref(self):
class SubDoc(EmbeddedDocument):
@ -157,14 +158,16 @@ class TestValidatorError(MongoDBTestCase):
s = SubDoc()
self.assertRaises(ValidationError, s.validate)
with pytest.raises(ValidationError):
s.validate()
d1.e = s
d2.e = s
del d1
self.assertRaises(ValidationError, d2.validate)
with pytest.raises(ValidationError):
d2.validate()
def test_parent_reference_in_child_document(self):
"""

View File

@ -2,7 +2,7 @@
import uuid
from bson import Binary
from nose.plugins.skip import SkipTest
import pytest
import six
from mongoengine import *
@ -31,8 +31,8 @@ class TestBinaryField(MongoDBTestCase):
attachment.save()
attachment_1 = Attachment.objects().first()
self.assertEqual(MIME_TYPE, attachment_1.content_type)
self.assertEqual(BLOB, six.binary_type(attachment_1.blob))
assert MIME_TYPE == attachment_1.content_type
assert BLOB == six.binary_type(attachment_1.blob)
def test_validation_succeeds(self):
"""Ensure that valid values can be assigned to binary fields.
@ -45,13 +45,15 @@ class TestBinaryField(MongoDBTestCase):
blob = BinaryField(max_bytes=4)
attachment_required = AttachmentRequired()
self.assertRaises(ValidationError, attachment_required.validate)
with pytest.raises(ValidationError):
attachment_required.validate()
attachment_required.blob = Binary(six.b("\xe6\x00\xc4\xff\x07"))
attachment_required.validate()
_5_BYTES = six.b("\xe6\x00\xc4\xff\x07")
_4_BYTES = six.b("\xe6\x00\xc4\xff")
self.assertRaises(ValidationError, AttachmentSizeLimit(blob=_5_BYTES).validate)
with pytest.raises(ValidationError):
AttachmentSizeLimit(blob=_5_BYTES).validate()
AttachmentSizeLimit(blob=_4_BYTES).validate()
def test_validation_fails(self):
@ -61,7 +63,8 @@ class TestBinaryField(MongoDBTestCase):
blob = BinaryField()
for invalid_data in (2, u"Im_a_unicode", ["some_str"]):
self.assertRaises(ValidationError, Attachment(blob=invalid_data).validate)
with pytest.raises(ValidationError):
Attachment(blob=invalid_data).validate()
def test__primary(self):
class Attachment(Document):
@ -70,10 +73,10 @@ class TestBinaryField(MongoDBTestCase):
Attachment.drop_collection()
binary_id = uuid.uuid4().bytes
att = Attachment(id=binary_id).save()
self.assertEqual(1, Attachment.objects.count())
self.assertEqual(1, Attachment.objects.filter(id=att.id).count())
assert 1 == Attachment.objects.count()
assert 1 == Attachment.objects.filter(id=att.id).count()
att.delete()
self.assertEqual(0, Attachment.objects.count())
assert 0 == Attachment.objects.count()
def test_primary_filter_by_binary_pk_as_str(self):
class Attachment(Document):
@ -82,9 +85,9 @@ class TestBinaryField(MongoDBTestCase):
Attachment.drop_collection()
binary_id = uuid.uuid4().bytes
att = Attachment(id=binary_id).save()
self.assertEqual(1, Attachment.objects.filter(id=binary_id).count())
assert 1 == Attachment.objects.filter(id=binary_id).count()
att.delete()
self.assertEqual(0, Attachment.objects.count())
assert 0 == Attachment.objects.count()
def test_match_querying_with_bytes(self):
class MyDocument(Document):
@ -94,7 +97,7 @@ class TestBinaryField(MongoDBTestCase):
doc = MyDocument(bin_field=BIN_VALUE).save()
matched_doc = MyDocument.objects(bin_field=BIN_VALUE).first()
self.assertEqual(matched_doc.id, doc.id)
assert matched_doc.id == doc.id
def test_match_querying_with_binary(self):
class MyDocument(Document):
@ -105,7 +108,7 @@ class TestBinaryField(MongoDBTestCase):
doc = MyDocument(bin_field=BIN_VALUE).save()
matched_doc = MyDocument.objects(bin_field=Binary(BIN_VALUE)).first()
self.assertEqual(matched_doc.id, doc.id)
assert matched_doc.id == doc.id
def test_modify_operation__set(self):
"""Ensures no regression of bug #1127"""
@ -119,11 +122,11 @@ class TestBinaryField(MongoDBTestCase):
doc = MyDocument.objects(some_field="test").modify(
upsert=True, new=True, set__bin_field=BIN_VALUE
)
self.assertEqual(doc.some_field, "test")
assert doc.some_field == "test"
if six.PY3:
self.assertEqual(doc.bin_field, BIN_VALUE)
assert doc.bin_field == BIN_VALUE
else:
self.assertEqual(doc.bin_field, Binary(BIN_VALUE))
assert doc.bin_field == Binary(BIN_VALUE)
def test_update_one(self):
"""Ensures no regression of bug #1127"""
@ -139,9 +142,9 @@ class TestBinaryField(MongoDBTestCase):
n_updated = MyDocument.objects(bin_field=bin_data).update_one(
bin_field=BIN_VALUE
)
self.assertEqual(n_updated, 1)
assert n_updated == 1
fetched = MyDocument.objects.with_id(doc.id)
if six.PY3:
self.assertEqual(fetched.bin_field, BIN_VALUE)
assert fetched.bin_field == BIN_VALUE
else:
self.assertEqual(fetched.bin_field, Binary(BIN_VALUE))
assert fetched.bin_field == Binary(BIN_VALUE)

View File

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
from mongoengine import *
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase, get_as_pymongo
@ -11,7 +12,7 @@ class TestBooleanField(MongoDBTestCase):
person = Person(admin=True)
person.save()
self.assertEqual(get_as_pymongo(person), {"_id": person.id, "admin": True})
assert get_as_pymongo(person) == {"_id": person.id, "admin": True}
def test_validation(self):
"""Ensure that invalid values cannot be assigned to boolean
@ -26,11 +27,14 @@ class TestBooleanField(MongoDBTestCase):
person.validate()
person.admin = 2
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.admin = "Yes"
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.admin = "False"
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
def test_weirdness_constructor(self):
"""When attribute is set in contructor, it gets cast into a bool
@ -42,7 +46,7 @@ class TestBooleanField(MongoDBTestCase):
admin = BooleanField()
new_person = Person(admin="False")
self.assertTrue(new_person.admin)
assert new_person.admin
new_person = Person(admin="0")
self.assertTrue(new_person.admin)
assert new_person.admin

View File

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
from decimal import Decimal
from mongoengine import *
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -46,29 +47,29 @@ class TestCachedReferenceField(MongoDBTestCase):
a = Animal(name="Leopard", tag="heavy")
a.save()
self.assertEqual(Animal._cached_reference_fields, [Ocorrence.animal])
assert Animal._cached_reference_fields == [Ocorrence.animal]
o = Ocorrence(person="teste", animal=a)
o.save()
p = Ocorrence(person="Wilson")
p.save()
self.assertEqual(Ocorrence.objects(animal=None).count(), 1)
assert Ocorrence.objects(animal=None).count() == 1
self.assertEqual(a.to_mongo(fields=["tag"]), {"tag": "heavy", "_id": a.pk})
assert a.to_mongo(fields=["tag"]) == {"tag": "heavy", "_id": a.pk}
self.assertEqual(o.to_mongo()["animal"]["tag"], "heavy")
assert o.to_mongo()["animal"]["tag"] == "heavy"
# counts
Ocorrence(person="teste 2").save()
Ocorrence(person="teste 3").save()
count = Ocorrence.objects(animal__tag="heavy").count()
self.assertEqual(count, 1)
assert count == 1
ocorrence = Ocorrence.objects(animal__tag="heavy").first()
self.assertEqual(ocorrence.person, "teste")
self.assertIsInstance(ocorrence.animal, Animal)
assert ocorrence.person == "teste"
assert isinstance(ocorrence.animal, Animal)
def test_with_decimal(self):
class PersonAuto(Document):
@ -88,10 +89,11 @@ class TestCachedReferenceField(MongoDBTestCase):
s = SocialTest(group="dev", person=p)
s.save()
self.assertEqual(
SocialTest.objects._collection.find_one({"person.salary": 7000.00}),
{"_id": s.pk, "group": s.group, "person": {"_id": p.pk, "salary": 7000.00}},
)
assert SocialTest.objects._collection.find_one({"person.salary": 7000.00}) == {
"_id": s.pk,
"group": s.group,
"person": {"_id": p.pk, "salary": 7000.00},
}
def test_cached_reference_field_reference(self):
class Group(Document):
@ -131,18 +133,15 @@ class TestCachedReferenceField(MongoDBTestCase):
s2 = SocialData(obs="testing 321", person=p3, tags=["tag3", "tag4"])
s2.save()
self.assertEqual(
SocialData.objects._collection.find_one({"tags": "tag2"}),
{
"_id": s1.pk,
"obs": "testing 123",
"tags": ["tag1", "tag2"],
"person": {"_id": p1.pk, "group": g1.pk},
},
)
assert SocialData.objects._collection.find_one({"tags": "tag2"}) == {
"_id": s1.pk,
"obs": "testing 123",
"tags": ["tag1", "tag2"],
"person": {"_id": p1.pk, "group": g1.pk},
}
self.assertEqual(SocialData.objects(person__group=g2).count(), 1)
self.assertEqual(SocialData.objects(person__group=g2).first(), s2)
assert SocialData.objects(person__group=g2).count() == 1
assert SocialData.objects(person__group=g2).first() == s2
def test_cached_reference_field_push_with_fields(self):
class Product(Document):
@ -157,26 +156,20 @@ class TestCachedReferenceField(MongoDBTestCase):
product1 = Product(name="abc").save()
product2 = Product(name="def").save()
basket = Basket(products=[product1]).save()
self.assertEqual(
Basket.objects._collection.find_one(),
{
"_id": basket.pk,
"products": [{"_id": product1.pk, "name": product1.name}],
},
)
assert Basket.objects._collection.find_one() == {
"_id": basket.pk,
"products": [{"_id": product1.pk, "name": product1.name}],
}
# push to list
basket.update(push__products=product2)
basket.reload()
self.assertEqual(
Basket.objects._collection.find_one(),
{
"_id": basket.pk,
"products": [
{"_id": product1.pk, "name": product1.name},
{"_id": product2.pk, "name": product2.name},
],
},
)
assert Basket.objects._collection.find_one() == {
"_id": basket.pk,
"products": [
{"_id": product1.pk, "name": product1.name},
{"_id": product2.pk, "name": product2.name},
],
}
def test_cached_reference_field_update_all(self):
class Person(Document):
@ -194,37 +187,31 @@ class TestCachedReferenceField(MongoDBTestCase):
a2.save()
a2 = Person.objects.with_id(a2.id)
self.assertEqual(a2.father.tp, a1.tp)
assert a2.father.tp == a1.tp
self.assertEqual(
dict(a2.to_mongo()),
{
"_id": a2.pk,
"name": u"Wilson Junior",
"tp": u"pf",
"father": {"_id": a1.pk, "tp": u"pj"},
},
)
assert dict(a2.to_mongo()) == {
"_id": a2.pk,
"name": u"Wilson Junior",
"tp": u"pf",
"father": {"_id": a1.pk, "tp": u"pj"},
}
self.assertEqual(Person.objects(father=a1)._query, {"father._id": a1.pk})
self.assertEqual(Person.objects(father=a1).count(), 1)
assert Person.objects(father=a1)._query == {"father._id": a1.pk}
assert Person.objects(father=a1).count() == 1
Person.objects.update(set__tp="pf")
Person.father.sync_all()
a2.reload()
self.assertEqual(
dict(a2.to_mongo()),
{
"_id": a2.pk,
"name": u"Wilson Junior",
"tp": u"pf",
"father": {"_id": a1.pk, "tp": u"pf"},
},
)
assert dict(a2.to_mongo()) == {
"_id": a2.pk,
"name": u"Wilson Junior",
"tp": u"pf",
"father": {"_id": a1.pk, "tp": u"pf"},
}
def test_cached_reference_fields_on_embedded_documents(self):
with self.assertRaises(InvalidDocumentError):
with pytest.raises(InvalidDocumentError):
class Test(Document):
name = StringField()
@ -255,15 +242,12 @@ class TestCachedReferenceField(MongoDBTestCase):
a1.save()
a2.reload()
self.assertEqual(
dict(a2.to_mongo()),
{
"_id": a2.pk,
"name": "Wilson Junior",
"tp": "pf",
"father": {"_id": a1.pk, "tp": "pf"},
},
)
assert dict(a2.to_mongo()) == {
"_id": a2.pk,
"name": "Wilson Junior",
"tp": "pf",
"father": {"_id": a1.pk, "tp": "pf"},
}
def test_cached_reference_auto_sync_disabled(self):
class Persone(Document):
@ -284,15 +268,12 @@ class TestCachedReferenceField(MongoDBTestCase):
a1.tp = "pf"
a1.save()
self.assertEqual(
Persone.objects._collection.find_one({"_id": a2.pk}),
{
"_id": a2.pk,
"name": "Wilson Junior",
"tp": "pf",
"father": {"_id": a1.pk, "tp": "pj"},
},
)
assert Persone.objects._collection.find_one({"_id": a2.pk}) == {
"_id": a2.pk,
"name": "Wilson Junior",
"tp": "pf",
"father": {"_id": a1.pk, "tp": "pj"},
}
def test_cached_reference_embedded_fields(self):
class Owner(EmbeddedDocument):
@ -320,28 +301,29 @@ class TestCachedReferenceField(MongoDBTestCase):
o = Ocorrence(person="teste", animal=a)
o.save()
self.assertEqual(
dict(a.to_mongo(fields=["tag", "owner.tp"])),
{"_id": a.pk, "tag": "heavy", "owner": {"t": "u"}},
)
self.assertEqual(o.to_mongo()["animal"]["tag"], "heavy")
self.assertEqual(o.to_mongo()["animal"]["owner"]["t"], "u")
assert dict(a.to_mongo(fields=["tag", "owner.tp"])) == {
"_id": a.pk,
"tag": "heavy",
"owner": {"t": "u"},
}
assert o.to_mongo()["animal"]["tag"] == "heavy"
assert o.to_mongo()["animal"]["owner"]["t"] == "u"
# Check to_mongo with fields
self.assertNotIn("animal", o.to_mongo(fields=["person"]))
assert "animal" not in o.to_mongo(fields=["person"])
# counts
Ocorrence(person="teste 2").save()
Ocorrence(person="teste 3").save()
count = Ocorrence.objects(animal__tag="heavy", animal__owner__tp="u").count()
self.assertEqual(count, 1)
assert count == 1
ocorrence = Ocorrence.objects(
animal__tag="heavy", animal__owner__tp="u"
).first()
self.assertEqual(ocorrence.person, "teste")
self.assertIsInstance(ocorrence.animal, Animal)
assert ocorrence.person == "teste"
assert isinstance(ocorrence.animal, Animal)
def test_cached_reference_embedded_list_fields(self):
class Owner(EmbeddedDocument):
@ -370,13 +352,14 @@ class TestCachedReferenceField(MongoDBTestCase):
o = Ocorrence(person="teste 2", animal=a)
o.save()
self.assertEqual(
dict(a.to_mongo(fields=["tag", "owner.tags"])),
{"_id": a.pk, "tag": "heavy", "owner": {"tags": ["cool", "funny"]}},
)
assert dict(a.to_mongo(fields=["tag", "owner.tags"])) == {
"_id": a.pk,
"tag": "heavy",
"owner": {"tags": ["cool", "funny"]},
}
self.assertEqual(o.to_mongo()["animal"]["tag"], "heavy")
self.assertEqual(o.to_mongo()["animal"]["owner"]["tags"], ["cool", "funny"])
assert o.to_mongo()["animal"]["tag"] == "heavy"
assert o.to_mongo()["animal"]["owner"]["tags"] == ["cool", "funny"]
# counts
Ocorrence(person="teste 2").save()
@ -385,10 +368,10 @@ class TestCachedReferenceField(MongoDBTestCase):
query = Ocorrence.objects(
animal__tag="heavy", animal__owner__tags="cool"
)._query
self.assertEqual(query, {"animal.owner.tags": "cool", "animal.tag": "heavy"})
assert query == {"animal.owner.tags": "cool", "animal.tag": "heavy"}
ocorrence = Ocorrence.objects(
animal__tag="heavy", animal__owner__tags="cool"
).first()
self.assertEqual(ocorrence.person, "teste 2")
self.assertIsInstance(ocorrence.animal, Animal)
assert ocorrence.person == "teste 2"
assert isinstance(ocorrence.animal, Animal)

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
import datetime
import math
import itertools
import math
import re
from mongoengine import *
@ -28,7 +28,7 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
assert log.date == d1
# Post UTC - microseconds are rounded (down) nearest millisecond - with
# default datetimefields
@ -36,7 +36,7 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
assert log.date == d1
# Pre UTC dates microseconds below 1000 are dropped - with default
# datetimefields
@ -44,7 +44,7 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
assert log.date == d1
# Pre UTC microseconds above 1000 is wonky - with default datetimefields
# log.date has an invalid microsecond value so I can't construct
@ -54,9 +54,9 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1)
assert log.date == d1
log1 = LogEntry.objects.get(date=d1)
self.assertEqual(log, log1)
assert log == log1
# Test string padding
microsecond = map(int, [math.pow(10, x) for x in range(6)])
@ -64,7 +64,7 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
for values in itertools.product([2014], mm, dd, hh, ii, ss, microsecond):
stored = LogEntry(date=datetime.datetime(*values)).to_mongo()["date"]
self.assertTrue(
assert (
re.match("^\d{4},\d{2},\d{2},\d{2},\d{2},\d{2},\d{6}$", stored)
is not None
)
@ -73,7 +73,7 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
stored = LogEntry(date_with_dots=datetime.datetime(2014, 1, 1)).to_mongo()[
"date_with_dots"
]
self.assertTrue(
assert (
re.match("^\d{4}.\d{2}.\d{2}.\d{2}.\d{2}.\d{2}.\d{6}$", stored) is not None
)
@ -93,40 +93,40 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
log.save()
log1 = LogEntry.objects.get(date=d1)
self.assertEqual(log, log1)
assert log == log1
# create extra 59 log entries for a total of 60
for i in range(1951, 2010):
d = datetime.datetime(i, 1, 1, 0, 0, 1, 999)
LogEntry(date=d).save()
self.assertEqual(LogEntry.objects.count(), 60)
assert LogEntry.objects.count() == 60
# Test ordering
logs = LogEntry.objects.order_by("date")
i = 0
while i < 59:
self.assertTrue(logs[i].date <= logs[i + 1].date)
assert logs[i].date <= logs[i + 1].date
i += 1
logs = LogEntry.objects.order_by("-date")
i = 0
while i < 59:
self.assertTrue(logs[i].date >= logs[i + 1].date)
assert logs[i].date >= logs[i + 1].date
i += 1
# Test searching
logs = LogEntry.objects.filter(date__gte=datetime.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 30)
assert logs.count() == 30
logs = LogEntry.objects.filter(date__lte=datetime.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 30)
assert logs.count() == 30
logs = LogEntry.objects.filter(
date__lte=datetime.datetime(2011, 1, 1),
date__gte=datetime.datetime(2000, 1, 1),
)
self.assertEqual(logs.count(), 10)
assert logs.count() == 10
LogEntry.drop_collection()
@ -137,17 +137,17 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
logs = list(LogEntry.objects.order_by("date"))
for next_idx, log in enumerate(logs[:-1], start=1):
next_log = logs[next_idx]
self.assertTrue(log.date < next_log.date)
assert log.date < next_log.date
logs = list(LogEntry.objects.order_by("-date"))
for next_idx, log in enumerate(logs[:-1], start=1):
next_log = logs[next_idx]
self.assertTrue(log.date > next_log.date)
assert log.date > next_log.date
logs = LogEntry.objects.filter(
date__lte=datetime.datetime(2015, 1, 1, 0, 0, 0, 10000)
)
self.assertEqual(logs.count(), 4)
assert logs.count() == 4
def test_no_default_value(self):
class Log(Document):
@ -156,11 +156,11 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
Log.drop_collection()
log = Log()
self.assertIsNone(log.timestamp)
assert log.timestamp is None
log.save()
fetched_log = Log.objects.with_id(log.id)
self.assertIsNone(fetched_log.timestamp)
assert fetched_log.timestamp is None
def test_default_static_value(self):
NOW = datetime.datetime.utcnow()
@ -171,11 +171,11 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
Log.drop_collection()
log = Log()
self.assertEqual(log.timestamp, NOW)
assert log.timestamp == NOW
log.save()
fetched_log = Log.objects.with_id(log.id)
self.assertEqual(fetched_log.timestamp, NOW)
assert fetched_log.timestamp == NOW
def test_default_callable(self):
NOW = datetime.datetime.utcnow()
@ -186,8 +186,8 @@ class ComplexDateTimeFieldTest(MongoDBTestCase):
Log.drop_collection()
log = Log()
self.assertGreaterEqual(log.timestamp, NOW)
assert log.timestamp >= NOW
log.save()
fetched_log = Log.objects.with_id(log.id)
self.assertGreaterEqual(fetched_log.timestamp, NOW)
assert fetched_log.timestamp >= NOW

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
import datetime
import pytest
import six
try:
@ -8,7 +10,6 @@ except ImportError:
dateutil = None
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -23,7 +24,8 @@ class TestDateField(MongoDBTestCase):
dt = DateField()
md = MyDoc(dt="")
self.assertRaises(ValidationError, md.save)
with pytest.raises(ValidationError):
md.save()
def test_date_from_whitespace_string(self):
"""
@ -35,7 +37,8 @@ class TestDateField(MongoDBTestCase):
dt = DateField()
md = MyDoc(dt=" ")
self.assertRaises(ValidationError, md.save)
with pytest.raises(ValidationError):
md.save()
def test_default_values_today(self):
"""Ensure that default field values are used when creating
@ -47,9 +50,9 @@ class TestDateField(MongoDBTestCase):
person = Person()
person.validate()
self.assertEqual(person.day, person.day)
self.assertEqual(person.day, datetime.date.today())
self.assertEqual(person._data["day"], person.day)
assert person.day == person.day
assert person.day == datetime.date.today()
assert person._data["day"] == person.day
def test_date(self):
"""Tests showing pymongo date fields
@ -67,7 +70,7 @@ class TestDateField(MongoDBTestCase):
log.date = datetime.date.today()
log.save()
log.reload()
self.assertEqual(log.date, datetime.date.today())
assert log.date == datetime.date.today()
d1 = datetime.datetime(1970, 1, 1, 0, 0, 1, 999)
d2 = datetime.datetime(1970, 1, 1, 0, 0, 1)
@ -75,16 +78,16 @@ class TestDateField(MongoDBTestCase):
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1.date())
self.assertEqual(log.date, d2.date())
assert log.date == d1.date()
assert log.date == d2.date()
d1 = datetime.datetime(1970, 1, 1, 0, 0, 1, 9999)
d2 = datetime.datetime(1970, 1, 1, 0, 0, 1, 9000)
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1.date())
self.assertEqual(log.date, d2.date())
assert log.date == d1.date()
assert log.date == d2.date()
if not six.PY3:
# Pre UTC dates microseconds below 1000 are dropped
@ -94,8 +97,8 @@ class TestDateField(MongoDBTestCase):
log.date = d1
log.save()
log.reload()
self.assertEqual(log.date, d1.date())
self.assertEqual(log.date, d2.date())
assert log.date == d1.date()
assert log.date == d2.date()
def test_regular_usage(self):
"""Tests for regular datetime fields"""
@ -113,35 +116,35 @@ class TestDateField(MongoDBTestCase):
for query in (d1, d1.isoformat(" ")):
log1 = LogEntry.objects.get(date=query)
self.assertEqual(log, log1)
assert log == log1
if dateutil:
log1 = LogEntry.objects.get(date=d1.isoformat("T"))
self.assertEqual(log, log1)
assert log == log1
# create additional 19 log entries for a total of 20
for i in range(1971, 1990):
d = datetime.datetime(i, 1, 1, 0, 0, 1)
LogEntry(date=d).save()
self.assertEqual(LogEntry.objects.count(), 20)
assert LogEntry.objects.count() == 20
# Test ordering
logs = LogEntry.objects.order_by("date")
i = 0
while i < 19:
self.assertTrue(logs[i].date <= logs[i + 1].date)
assert logs[i].date <= logs[i + 1].date
i += 1
logs = LogEntry.objects.order_by("-date")
i = 0
while i < 19:
self.assertTrue(logs[i].date >= logs[i + 1].date)
assert logs[i].date >= logs[i + 1].date
i += 1
# Test searching
logs = LogEntry.objects.filter(date__gte=datetime.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 10)
assert logs.count() == 10
def test_validation(self):
"""Ensure that invalid values cannot be assigned to datetime
@ -166,6 +169,8 @@ class TestDateField(MongoDBTestCase):
log.validate()
log.time = -1
self.assertRaises(ValidationError, log.validate)
with pytest.raises(ValidationError):
log.validate()
log.time = "ABC"
self.assertRaises(ValidationError, log.validate)
with pytest.raises(ValidationError):
log.validate()

View File

@ -1,5 +1,7 @@
# -*- coding: utf-8 -*-
import datetime as dt
import pytest
import six
try:
@ -24,7 +26,8 @@ class TestDateTimeField(MongoDBTestCase):
dt = DateTimeField()
md = MyDoc(dt="")
self.assertRaises(ValidationError, md.save)
with pytest.raises(ValidationError):
md.save()
def test_datetime_from_whitespace_string(self):
"""
@ -36,7 +39,8 @@ class TestDateTimeField(MongoDBTestCase):
dt = DateTimeField()
md = MyDoc(dt=" ")
self.assertRaises(ValidationError, md.save)
with pytest.raises(ValidationError):
md.save()
def test_default_value_utcnow(self):
"""Ensure that default field values are used when creating
@ -50,11 +54,9 @@ class TestDateTimeField(MongoDBTestCase):
person = Person()
person.validate()
person_created_t0 = person.created
self.assertLess(person.created - utcnow, dt.timedelta(seconds=1))
self.assertEqual(
person_created_t0, person.created
) # make sure it does not change
self.assertEqual(person._data["created"], person.created)
assert person.created - utcnow < dt.timedelta(seconds=1)
assert person_created_t0 == person.created # make sure it does not change
assert person._data["created"] == person.created
def test_handling_microseconds(self):
"""Tests showing pymongo datetime fields handling of microseconds.
@ -74,7 +76,7 @@ class TestDateTimeField(MongoDBTestCase):
log.date = dt.date.today()
log.save()
log.reload()
self.assertEqual(log.date.date(), dt.date.today())
assert log.date.date() == dt.date.today()
# Post UTC - microseconds are rounded (down) nearest millisecond and
# dropped
@ -84,8 +86,8 @@ class TestDateTimeField(MongoDBTestCase):
log.date = d1
log.save()
log.reload()
self.assertNotEqual(log.date, d1)
self.assertEqual(log.date, d2)
assert log.date != d1
assert log.date == d2
# Post UTC - microseconds are rounded (down) nearest millisecond
d1 = dt.datetime(1970, 1, 1, 0, 0, 1, 9999)
@ -93,8 +95,8 @@ class TestDateTimeField(MongoDBTestCase):
log.date = d1
log.save()
log.reload()
self.assertNotEqual(log.date, d1)
self.assertEqual(log.date, d2)
assert log.date != d1
assert log.date == d2
if not six.PY3:
# Pre UTC dates microseconds below 1000 are dropped
@ -104,8 +106,8 @@ class TestDateTimeField(MongoDBTestCase):
log.date = d1
log.save()
log.reload()
self.assertNotEqual(log.date, d1)
self.assertEqual(log.date, d2)
assert log.date != d1
assert log.date == d2
def test_regular_usage(self):
"""Tests for regular datetime fields"""
@ -123,43 +125,43 @@ class TestDateTimeField(MongoDBTestCase):
for query in (d1, d1.isoformat(" ")):
log1 = LogEntry.objects.get(date=query)
self.assertEqual(log, log1)
assert log == log1
if dateutil:
log1 = LogEntry.objects.get(date=d1.isoformat("T"))
self.assertEqual(log, log1)
assert log == log1
# create additional 19 log entries for a total of 20
for i in range(1971, 1990):
d = dt.datetime(i, 1, 1, 0, 0, 1)
LogEntry(date=d).save()
self.assertEqual(LogEntry.objects.count(), 20)
assert LogEntry.objects.count() == 20
# Test ordering
logs = LogEntry.objects.order_by("date")
i = 0
while i < 19:
self.assertTrue(logs[i].date <= logs[i + 1].date)
assert logs[i].date <= logs[i + 1].date
i += 1
logs = LogEntry.objects.order_by("-date")
i = 0
while i < 19:
self.assertTrue(logs[i].date >= logs[i + 1].date)
assert logs[i].date >= logs[i + 1].date
i += 1
# Test searching
logs = LogEntry.objects.filter(date__gte=dt.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 10)
assert logs.count() == 10
logs = LogEntry.objects.filter(date__lte=dt.datetime(1980, 1, 1))
self.assertEqual(logs.count(), 10)
assert logs.count() == 10
logs = LogEntry.objects.filter(
date__lte=dt.datetime(1980, 1, 1), date__gte=dt.datetime(1975, 1, 1)
)
self.assertEqual(logs.count(), 5)
assert logs.count() == 5
def test_datetime_validation(self):
"""Ensure that invalid values cannot be assigned to datetime
@ -187,15 +189,20 @@ class TestDateTimeField(MongoDBTestCase):
log.validate()
log.time = -1
self.assertRaises(ValidationError, log.validate)
with pytest.raises(ValidationError):
log.validate()
log.time = "ABC"
self.assertRaises(ValidationError, log.validate)
with pytest.raises(ValidationError):
log.validate()
log.time = "2019-05-16 21:GARBAGE:12"
self.assertRaises(ValidationError, log.validate)
with pytest.raises(ValidationError):
log.validate()
log.time = "2019-05-16 21:42:57.GARBAGE"
self.assertRaises(ValidationError, log.validate)
with pytest.raises(ValidationError):
log.validate()
log.time = "2019-05-16 21:42:57.123.456"
self.assertRaises(ValidationError, log.validate)
with pytest.raises(ValidationError):
log.validate()
def test_parse_datetime_as_str(self):
class DTDoc(Document):
@ -206,15 +213,16 @@ class TestDateTimeField(MongoDBTestCase):
# make sure that passing a parsable datetime works
dtd = DTDoc()
dtd.date = date_str
self.assertIsInstance(dtd.date, six.string_types)
assert isinstance(dtd.date, six.string_types)
dtd.save()
dtd.reload()
self.assertIsInstance(dtd.date, dt.datetime)
self.assertEqual(str(dtd.date), date_str)
assert isinstance(dtd.date, dt.datetime)
assert str(dtd.date) == date_str
dtd.date = "January 1st, 9999999999"
self.assertRaises(ValidationError, dtd.validate)
with pytest.raises(ValidationError):
dtd.validate()
class TestDateTimeTzAware(MongoDBTestCase):
@ -235,4 +243,4 @@ class TestDateTimeTzAware(MongoDBTestCase):
log = LogEntry.objects.first()
log.time = dt.datetime(2013, 1, 1, 0, 0, 0)
self.assertEqual(["time"], log._changed_fields)
assert ["time"] == log._changed_fields

View File

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
from decimal import Decimal
from mongoengine import *
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -18,21 +19,26 @@ class TestDecimalField(MongoDBTestCase):
Person(height=Decimal("1.89")).save()
person = Person.objects.first()
self.assertEqual(person.height, Decimal("1.89"))
assert person.height == Decimal("1.89")
person.height = "2.0"
person.save()
person.height = 0.01
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.height = Decimal("0.01")
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.height = Decimal("4.0")
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.height = "something invalid"
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person_2 = Person(height="something invalid")
self.assertRaises(ValidationError, person_2.validate)
with pytest.raises(ValidationError):
person_2.validate()
def test_comparison(self):
class Person(Document):
@ -45,11 +51,11 @@ class TestDecimalField(MongoDBTestCase):
Person(money=8).save()
Person(money=10).save()
self.assertEqual(2, Person.objects(money__gt=Decimal("7")).count())
self.assertEqual(2, Person.objects(money__gt=7).count())
self.assertEqual(2, Person.objects(money__gt="7").count())
assert 2 == Person.objects(money__gt=Decimal("7")).count()
assert 2 == Person.objects(money__gt=7).count()
assert 2 == Person.objects(money__gt="7").count()
self.assertEqual(3, Person.objects(money__gte="7").count())
assert 3 == Person.objects(money__gte="7").count()
def test_storage(self):
class Person(Document):
@ -87,7 +93,7 @@ class TestDecimalField(MongoDBTestCase):
]
expected.extend(expected)
actual = list(Person.objects.exclude("id").as_pymongo())
self.assertEqual(expected, actual)
assert expected == actual
# How it comes out locally
expected = [
@ -101,4 +107,4 @@ class TestDecimalField(MongoDBTestCase):
expected.extend(expected)
for field_name in ["float_value", "string_value"]:
actual = list(Person.objects().scalar(field_name))
self.assertEqual(expected, actual)
assert expected == actual

View File

@ -1,6 +1,9 @@
# -*- coding: utf-8 -*-
import pytest
from mongoengine import *
from mongoengine.base import BaseDict
from mongoengine.mongodb_support import MONGODB_36, get_mongodb_version
from tests.utils import MongoDBTestCase, get_as_pymongo
@ -14,7 +17,7 @@ class TestDictField(MongoDBTestCase):
info = {"testkey": "testvalue"}
post = BlogPost(info=info).save()
self.assertEqual(get_as_pymongo(post), {"_id": post.id, "info": info})
assert get_as_pymongo(post) == {"_id": post.id, "info": info}
def test_general_things(self):
"""Ensure that dict types work as expected."""
@ -26,25 +29,42 @@ class TestDictField(MongoDBTestCase):
post = BlogPost()
post.info = "my post"
self.assertRaises(ValidationError, post.validate)
with pytest.raises(ValidationError):
post.validate()
post.info = ["test", "test"]
self.assertRaises(ValidationError, post.validate)
with pytest.raises(ValidationError):
post.validate()
post.info = {"$title": "test"}
self.assertRaises(ValidationError, post.validate)
with pytest.raises(ValidationError):
post.validate()
post.info = {"nested": {"$title": "test"}}
self.assertRaises(ValidationError, post.validate)
with pytest.raises(ValidationError):
post.validate()
post.info = {"the.title": "test"}
self.assertRaises(ValidationError, post.validate)
post.info = {"nested": {"the.title": "test"}}
self.assertRaises(ValidationError, post.validate)
post.info = {"$title.test": "test"}
with pytest.raises(ValidationError):
post.validate()
post.info = {1: "test"}
self.assertRaises(ValidationError, post.validate)
with pytest.raises(ValidationError):
post.validate()
post.info = {"nested": {"the.title": "test"}}
if get_mongodb_version() < MONGODB_36:
with pytest.raises(ValidationError):
post.validate()
else:
post.validate()
post.info = {"dollar_and_dot": {"te$st.test": "test"}}
if get_mongodb_version() < MONGODB_36:
with pytest.raises(ValidationError):
post.validate()
else:
post.validate()
post.info = {"title": "test"}
post.save()
@ -61,33 +81,27 @@ class TestDictField(MongoDBTestCase):
post.info = {"details": {"test": 3}}
post.save()
self.assertEqual(BlogPost.objects.count(), 4)
self.assertEqual(BlogPost.objects.filter(info__title__exact="test").count(), 1)
self.assertEqual(
BlogPost.objects.filter(info__details__test__exact="test").count(), 1
)
assert BlogPost.objects.count() == 4
assert BlogPost.objects.filter(info__title__exact="test").count() == 1
assert BlogPost.objects.filter(info__details__test__exact="test").count() == 1
post = BlogPost.objects.filter(info__title__exact="dollar_sign").first()
self.assertIn("te$t", post["info"]["details"])
assert "te$t" in post["info"]["details"]
# Confirm handles non strings or non existing keys
self.assertEqual(
BlogPost.objects.filter(info__details__test__exact=5).count(), 0
)
self.assertEqual(
BlogPost.objects.filter(info__made_up__test__exact="test").count(), 0
)
assert BlogPost.objects.filter(info__details__test__exact=5).count() == 0
assert BlogPost.objects.filter(info__made_up__test__exact="test").count() == 0
post = BlogPost.objects.create(info={"title": "original"})
post.info.update({"title": "updated"})
post.save()
post.reload()
self.assertEqual("updated", post.info["title"])
assert "updated" == post.info["title"]
post.info.setdefault("authors", [])
post.save()
post.reload()
self.assertEqual([], post.info["authors"])
assert [] == post.info["authors"]
def test_dictfield_dump_document(self):
"""Ensure a DictField can handle another document's dump."""
@ -114,10 +128,8 @@ class TestDictField(MongoDBTestCase):
).save()
doc = Doc(field=to_embed.to_mongo().to_dict())
doc.save()
self.assertIsInstance(doc.field, dict)
self.assertEqual(
doc.field, {"_id": 2, "recursive": {"_id": 1, "recursive": {}}}
)
assert isinstance(doc.field, dict)
assert doc.field == {"_id": 2, "recursive": {"_id": 1, "recursive": {}}}
# Same thing with a Document with a _cls field
to_embed_recursive = ToEmbedChild(id=1).save()
to_embed_child = ToEmbedChild(
@ -125,7 +137,7 @@ class TestDictField(MongoDBTestCase):
).save()
doc = Doc(field=to_embed_child.to_mongo().to_dict())
doc.save()
self.assertIsInstance(doc.field, dict)
assert isinstance(doc.field, dict)
expected = {
"_id": 2,
"_cls": "ToEmbedParent.ToEmbedChild",
@ -135,7 +147,7 @@ class TestDictField(MongoDBTestCase):
"recursive": {},
},
}
self.assertEqual(doc.field, expected)
assert doc.field == expected
def test_dictfield_strict(self):
"""Ensure that dict field handles validation if provided a strict field type."""
@ -150,7 +162,7 @@ class TestDictField(MongoDBTestCase):
e.save()
# try creating an invalid mapping
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
e.mapping["somestring"] = "abc"
e.save()
@ -184,22 +196,21 @@ class TestDictField(MongoDBTestCase):
e.save()
e2 = Simple.objects.get(id=e.id)
self.assertIsInstance(e2.mapping["somestring"], StringSetting)
self.assertIsInstance(e2.mapping["someint"], IntegerSetting)
assert isinstance(e2.mapping["somestring"], StringSetting)
assert isinstance(e2.mapping["someint"], IntegerSetting)
# Test querying
self.assertEqual(Simple.objects.filter(mapping__someint__value=42).count(), 1)
self.assertEqual(
Simple.objects.filter(mapping__nested_dict__number=1).count(), 1
assert Simple.objects.filter(mapping__someint__value=42).count() == 1
assert Simple.objects.filter(mapping__nested_dict__number=1).count() == 1
assert (
Simple.objects.filter(mapping__nested_dict__complex__value=42).count() == 1
)
self.assertEqual(
Simple.objects.filter(mapping__nested_dict__complex__value=42).count(), 1
assert (
Simple.objects.filter(mapping__nested_dict__list__0__value=42).count() == 1
)
self.assertEqual(
Simple.objects.filter(mapping__nested_dict__list__0__value=42).count(), 1
)
self.assertEqual(
Simple.objects.filter(mapping__nested_dict__list__1__value="foo").count(), 1
assert (
Simple.objects.filter(mapping__nested_dict__list__1__value="foo").count()
== 1
)
# Confirm can update
@ -207,11 +218,13 @@ class TestDictField(MongoDBTestCase):
Simple.objects().update(
set__mapping__nested_dict__list__1=StringSetting(value="Boo")
)
self.assertEqual(
Simple.objects.filter(mapping__nested_dict__list__1__value="foo").count(), 0
assert (
Simple.objects.filter(mapping__nested_dict__list__1__value="foo").count()
== 0
)
self.assertEqual(
Simple.objects.filter(mapping__nested_dict__list__1__value="Boo").count(), 1
assert (
Simple.objects.filter(mapping__nested_dict__list__1__value="Boo").count()
== 1
)
def test_push_dict(self):
@ -221,12 +234,12 @@ class TestDictField(MongoDBTestCase):
doc = MyModel(events=[{"a": 1}]).save()
raw_doc = get_as_pymongo(doc)
expected_raw_doc = {"_id": doc.id, "events": [{"a": 1}]}
self.assertEqual(raw_doc, expected_raw_doc)
assert raw_doc == expected_raw_doc
MyModel.objects(id=doc.id).update(push__events={})
raw_doc = get_as_pymongo(doc)
expected_raw_doc = {"_id": doc.id, "events": [{"a": 1}, {}]}
self.assertEqual(raw_doc, expected_raw_doc)
assert raw_doc == expected_raw_doc
def test_ensure_unique_default_instances(self):
"""Ensure that every field has it's own unique default instance."""
@ -239,8 +252,8 @@ class TestDictField(MongoDBTestCase):
d1.data["foo"] = "bar"
d1.data2["foo"] = "bar"
d2 = D()
self.assertEqual(d2.data, {})
self.assertEqual(d2.data2, {})
assert d2.data == {}
assert d2.data2 == {}
def test_dict_field_invalid_dict_value(self):
class DictFieldTest(Document):
@ -250,11 +263,13 @@ class TestDictField(MongoDBTestCase):
test = DictFieldTest(dictionary=None)
test.dictionary # Just access to test getter
self.assertRaises(ValidationError, test.validate)
with pytest.raises(ValidationError):
test.validate()
test = DictFieldTest(dictionary=False)
test.dictionary # Just access to test getter
self.assertRaises(ValidationError, test.validate)
with pytest.raises(ValidationError):
test.validate()
def test_dict_field_raises_validation_error_if_wrongly_assign_embedded_doc(self):
class DictFieldTest(Document):
@ -267,12 +282,12 @@ class TestDictField(MongoDBTestCase):
embed = Embedded(name="garbage")
doc = DictFieldTest(dictionary=embed)
with self.assertRaises(ValidationError) as ctx_err:
with pytest.raises(ValidationError) as exc_info:
doc.validate()
self.assertIn("'dictionary'", str(ctx_err.exception))
self.assertIn(
"Only dictionaries may be used in a DictField", str(ctx_err.exception)
)
error_msg = str(exc_info.value)
assert "'dictionary'" in error_msg
assert "Only dictionaries may be used in a DictField" in error_msg
def test_atomic_update_dict_field(self):
"""Ensure that the entire DictField can be atomically updated."""
@ -287,11 +302,11 @@ class TestDictField(MongoDBTestCase):
e.save()
e.update(set__mapping={"ints": [3, 4]})
e.reload()
self.assertEqual(BaseDict, type(e.mapping))
self.assertEqual({"ints": [3, 4]}, e.mapping)
assert isinstance(e.mapping, BaseDict)
assert {"ints": [3, 4]} == e.mapping
# try creating an invalid mapping
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
e.update(set__mapping={"somestrings": ["foo", "bar"]})
def test_dictfield_with_referencefield_complex_nesting_cases(self):
@ -329,13 +344,13 @@ class TestDictField(MongoDBTestCase):
e.save()
s = Simple.objects.first()
self.assertIsInstance(s.mapping0["someint"], Doc)
self.assertIsInstance(s.mapping1["someint"], Doc)
self.assertIsInstance(s.mapping2["someint"][0], Doc)
self.assertIsInstance(s.mapping3["someint"][0], Doc)
self.assertIsInstance(s.mapping4["someint"]["d"], Doc)
self.assertIsInstance(s.mapping5["someint"]["d"], Doc)
self.assertIsInstance(s.mapping6["someint"][0]["d"], Doc)
self.assertIsInstance(s.mapping7["someint"][0]["d"], Doc)
self.assertIsInstance(s.mapping8["someint"][0]["d"][0], Doc)
self.assertIsInstance(s.mapping9["someint"][0]["d"][0], Doc)
assert isinstance(s.mapping0["someint"], Doc)
assert isinstance(s.mapping1["someint"], Doc)
assert isinstance(s.mapping2["someint"][0], Doc)
assert isinstance(s.mapping3["someint"][0], Doc)
assert isinstance(s.mapping4["someint"]["d"], Doc)
assert isinstance(s.mapping5["someint"]["d"], Doc)
assert isinstance(s.mapping6["someint"][0]["d"], Doc)
assert isinstance(s.mapping7["someint"][0]["d"], Doc)
assert isinstance(s.mapping8["someint"][0]["d"][0], Doc)
assert isinstance(s.mapping9["someint"][0]["d"][0], Doc)

View File

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
import sys
from unittest import SkipTest
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -27,7 +27,8 @@ class TestEmailField(MongoDBTestCase):
user.validate()
user = User(email="ross@example.com.")
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
# unicode domain
user = User(email=u"user@пример.рф")
@ -35,24 +36,22 @@ class TestEmailField(MongoDBTestCase):
# invalid unicode domain
user = User(email=u"user@пример")
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
# invalid data type
user = User(email=123)
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
def test_email_field_unicode_user(self):
# Don't run this test on pypy3, which doesn't support unicode regex:
# https://bitbucket.org/pypy/pypy/issues/1821/regular-expression-doesnt-find-unicode
if sys.version_info[:2] == (3, 2):
raise SkipTest("unicode email addresses are not supported on PyPy 3")
class User(Document):
email = EmailField()
# unicode user shouldn't validate by default...
user = User(email=u"Dörte@Sörensen.example.com")
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
# ...but it should be fine with allow_utf8_user set to True
class User(Document):
@ -67,7 +66,8 @@ class TestEmailField(MongoDBTestCase):
# localhost domain shouldn't validate by default...
user = User(email="me@localhost")
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
# ...but it should be fine if it's whitelisted
class User(Document):
@ -82,9 +82,10 @@ class TestEmailField(MongoDBTestCase):
invalid_idn = ".google.com"
user = User(email="me@%s" % invalid_idn)
with self.assertRaises(ValidationError) as ctx_err:
with pytest.raises(ValidationError) as exc_info:
user.validate()
self.assertIn("domain failed IDN encoding", str(ctx_err.exception))
assert "domain failed IDN encoding" in str(exc_info.value)
def test_email_field_ip_domain(self):
class User(Document):
@ -96,13 +97,16 @@ class TestEmailField(MongoDBTestCase):
# IP address as a domain shouldn't validate by default...
user = User(email=valid_ipv4)
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
user = User(email=valid_ipv6)
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
user = User(email=invalid_ip)
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
# ...but it should be fine with allow_ip_domain set to True
class User(Document):
@ -116,7 +120,8 @@ class TestEmailField(MongoDBTestCase):
# invalid IP should still fail validation
user = User(email=invalid_ip)
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
def test_email_field_honors_regex(self):
class User(Document):
@ -124,8 +129,9 @@ class TestEmailField(MongoDBTestCase):
# Fails regex validation
user = User(email="me@foo.com")
self.assertRaises(ValidationError, user.validate)
with pytest.raises(ValidationError):
user.validate()
# Passes regex validation
user = User(email="me@example.com")
self.assertIsNone(user.validate())
assert user.validate() is None

View File

@ -1,17 +1,17 @@
# -*- coding: utf-8 -*-
import pytest
from mongoengine import (
Document,
StringField,
ValidationError,
EmbeddedDocument,
EmbeddedDocumentField,
InvalidQueryError,
LookUpError,
IntField,
GenericEmbeddedDocumentField,
IntField,
InvalidQueryError,
ListField,
EmbeddedDocumentListField,
ReferenceField,
LookUpError,
StringField,
ValidationError,
)
from tests.utils import MongoDBTestCase
@ -23,13 +23,13 @@ class TestEmbeddedDocumentField(MongoDBTestCase):
name = StringField()
field = EmbeddedDocumentField(MyDoc)
self.assertEqual(field.document_type_obj, MyDoc)
assert field.document_type_obj == MyDoc
field2 = EmbeddedDocumentField("MyDoc")
self.assertEqual(field2.document_type_obj, "MyDoc")
assert field2.document_type_obj == "MyDoc"
def test___init___throw_error_if_document_type_is_not_EmbeddedDocument(self):
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
EmbeddedDocumentField(dict)
def test_document_type_throw_error_if_not_EmbeddedDocument_subclass(self):
@ -37,11 +37,11 @@ class TestEmbeddedDocumentField(MongoDBTestCase):
name = StringField()
emb = EmbeddedDocumentField("MyDoc")
with self.assertRaises(ValidationError) as ctx:
with pytest.raises(ValidationError) as exc_info:
emb.document_type
self.assertIn(
"Invalid embedded document class provided to an EmbeddedDocumentField",
str(ctx.exception),
assert (
"Invalid embedded document class provided to an EmbeddedDocumentField"
in str(exc_info.value)
)
def test_embedded_document_field_only_allow_subclasses_of_embedded_document(self):
@ -49,12 +49,12 @@ class TestEmbeddedDocumentField(MongoDBTestCase):
class MyDoc(Document):
name = StringField()
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
class MyFailingDoc(Document):
emb = EmbeddedDocumentField(MyDoc)
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
class MyFailingdoc2(Document):
emb = EmbeddedDocumentField("MyDoc")
@ -73,24 +73,24 @@ class TestEmbeddedDocumentField(MongoDBTestCase):
p = Person(settings=AdminSettings(foo1="bar1", foo2="bar2"), name="John").save()
# Test non exiting attribute
with self.assertRaises(InvalidQueryError) as ctx_err:
with pytest.raises(InvalidQueryError) as exc_info:
Person.objects(settings__notexist="bar").first()
self.assertEqual(unicode(ctx_err.exception), u'Cannot resolve field "notexist"')
assert unicode(exc_info.value) == u'Cannot resolve field "notexist"'
with self.assertRaises(LookUpError):
with pytest.raises(LookUpError):
Person.objects.only("settings.notexist")
# Test existing attribute
self.assertEqual(Person.objects(settings__foo1="bar1").first().id, p.id)
assert Person.objects(settings__foo1="bar1").first().id == p.id
only_p = Person.objects.only("settings.foo1").first()
self.assertEqual(only_p.settings.foo1, p.settings.foo1)
self.assertIsNone(only_p.settings.foo2)
self.assertIsNone(only_p.name)
assert only_p.settings.foo1 == p.settings.foo1
assert only_p.settings.foo2 is None
assert only_p.name is None
exclude_p = Person.objects.exclude("settings.foo1").first()
self.assertIsNone(exclude_p.settings.foo1)
self.assertEqual(exclude_p.settings.foo2, p.settings.foo2)
self.assertEqual(exclude_p.name, p.name)
assert exclude_p.settings.foo1 is None
assert exclude_p.settings.foo2 == p.settings.foo2
assert exclude_p.name == p.name
def test_query_embedded_document_attribute_with_inheritance(self):
class BaseSettings(EmbeddedDocument):
@ -109,17 +109,17 @@ class TestEmbeddedDocumentField(MongoDBTestCase):
p.save()
# Test non exiting attribute
with self.assertRaises(InvalidQueryError) as ctx_err:
self.assertEqual(Person.objects(settings__notexist="bar").first().id, p.id)
self.assertEqual(unicode(ctx_err.exception), u'Cannot resolve field "notexist"')
with pytest.raises(InvalidQueryError) as exc_info:
assert Person.objects(settings__notexist="bar").first().id == p.id
assert unicode(exc_info.value) == u'Cannot resolve field "notexist"'
# Test existing attribute
self.assertEqual(Person.objects(settings__base_foo="basefoo").first().id, p.id)
self.assertEqual(Person.objects(settings__sub_foo="subfoo").first().id, p.id)
assert Person.objects(settings__base_foo="basefoo").first().id == p.id
assert Person.objects(settings__sub_foo="subfoo").first().id == p.id
only_p = Person.objects.only("settings.base_foo", "settings._cls").first()
self.assertEqual(only_p.settings.base_foo, "basefoo")
self.assertIsNone(only_p.settings.sub_foo)
assert only_p.settings.base_foo == "basefoo"
assert only_p.settings.sub_foo is None
def test_query_list_embedded_document_with_inheritance(self):
class Post(EmbeddedDocument):
@ -139,14 +139,14 @@ class TestEmbeddedDocumentField(MongoDBTestCase):
record_text = Record(posts=[TextPost(content="a", title="foo")]).save()
records = list(Record.objects(posts__author=record_movie.posts[0].author))
self.assertEqual(len(records), 1)
self.assertEqual(records[0].id, record_movie.id)
assert len(records) == 1
assert records[0].id == record_movie.id
records = list(Record.objects(posts__content=record_text.posts[0].content))
self.assertEqual(len(records), 1)
self.assertEqual(records[0].id, record_text.id)
assert len(records) == 1
assert records[0].id == record_text.id
self.assertEqual(Record.objects(posts__title="foo").count(), 2)
assert Record.objects(posts__title="foo").count() == 2
class TestGenericEmbeddedDocumentField(MongoDBTestCase):
@ -169,13 +169,13 @@ class TestGenericEmbeddedDocumentField(MongoDBTestCase):
person.save()
person = Person.objects.first()
self.assertIsInstance(person.like, Car)
assert isinstance(person.like, Car)
person.like = Dish(food="arroz", number=15)
person.save()
person = Person.objects.first()
self.assertIsInstance(person.like, Dish)
assert isinstance(person.like, Dish)
def test_generic_embedded_document_choices(self):
"""Ensure you can limit GenericEmbeddedDocument choices."""
@ -195,13 +195,14 @@ class TestGenericEmbeddedDocumentField(MongoDBTestCase):
person = Person(name="Test User")
person.like = Car(name="Fiat")
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.like = Dish(food="arroz", number=15)
person.save()
person = Person.objects.first()
self.assertIsInstance(person.like, Dish)
assert isinstance(person.like, Dish)
def test_generic_list_embedded_document_choices(self):
"""Ensure you can limit GenericEmbeddedDocument choices inside
@ -223,13 +224,14 @@ class TestGenericEmbeddedDocumentField(MongoDBTestCase):
person = Person(name="Test User")
person.likes = [Car(name="Fiat")]
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.likes = [Dish(food="arroz", number=15)]
person.save()
person = Person.objects.first()
self.assertIsInstance(person.likes[0], Dish)
assert isinstance(person.likes[0], Dish)
def test_choices_validation_documents(self):
"""
@ -265,7 +267,8 @@ class TestGenericEmbeddedDocumentField(MongoDBTestCase):
# Single Entry Failure
post = BlogPost(comments=[ModeratorComments(author="mod1", message="message1")])
self.assertRaises(ValidationError, post.save)
with pytest.raises(ValidationError):
post.save()
# Mixed Entry Failure
post = BlogPost(
@ -274,7 +277,8 @@ class TestGenericEmbeddedDocumentField(MongoDBTestCase):
UserComments(author="user2", message="message2"),
]
)
self.assertRaises(ValidationError, post.save)
with pytest.raises(ValidationError):
post.save()
def test_choices_validation_documents_inheritance(self):
"""
@ -313,16 +317,16 @@ class TestGenericEmbeddedDocumentField(MongoDBTestCase):
p2 = Person(settings=NonAdminSettings(foo2="bar2")).save()
# Test non exiting attribute
with self.assertRaises(InvalidQueryError) as ctx_err:
with pytest.raises(InvalidQueryError) as exc_info:
Person.objects(settings__notexist="bar").first()
self.assertEqual(unicode(ctx_err.exception), u'Cannot resolve field "notexist"')
assert unicode(exc_info.value) == u'Cannot resolve field "notexist"'
with self.assertRaises(LookUpError):
with pytest.raises(LookUpError):
Person.objects.only("settings.notexist")
# Test existing attribute
self.assertEqual(Person.objects(settings__foo1="bar1").first().id, p1.id)
self.assertEqual(Person.objects(settings__foo2="bar2").first().id, p2.id)
assert Person.objects(settings__foo1="bar1").first().id == p1.id
assert Person.objects(settings__foo2="bar2").first().id == p2.id
def test_query_generic_embedded_document_attribute_with_inheritance(self):
class BaseSettings(EmbeddedDocument):
@ -341,10 +345,10 @@ class TestGenericEmbeddedDocumentField(MongoDBTestCase):
p.save()
# Test non exiting attribute
with self.assertRaises(InvalidQueryError) as ctx_err:
self.assertEqual(Person.objects(settings__notexist="bar").first().id, p.id)
self.assertEqual(unicode(ctx_err.exception), u'Cannot resolve field "notexist"')
with pytest.raises(InvalidQueryError) as exc_info:
assert Person.objects(settings__notexist="bar").first().id == p.id
assert unicode(exc_info.value) == u'Cannot resolve field "notexist"'
# Test existing attribute
self.assertEqual(Person.objects(settings__base_foo="basefoo").first().id, p.id)
self.assertEqual(Person.objects(settings__sub_foo="subfoo").first().id, p.id)
assert Person.objects(settings__base_foo="basefoo").first().id == p.id
assert Person.objects(settings__sub_foo="subfoo").first().id == p.id

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,7 @@ import tempfile
import unittest
import gridfs
from nose.plugins.skip import SkipTest
import pytest
import six
from mongoengine import *
@ -21,6 +21,8 @@ except ImportError:
from tests.utils import MongoDBTestCase
require_pil = pytest.mark.skipif(not HAS_PIL, reason="PIL not installed")
TEST_IMAGE_PATH = os.path.join(os.path.dirname(__file__), "mongoengine.png")
TEST_IMAGE2_PATH = os.path.join(os.path.dirname(__file__), "mongodb_leaf.png")
@ -64,13 +66,13 @@ class TestFileField(MongoDBTestCase):
putfile.save()
result = PutFile.objects.first()
self.assertEqual(putfile, result)
self.assertEqual(
"%s" % result.the_file,
"<GridFSProxy: hello (%s)>" % result.the_file.grid_id,
assert putfile == result
assert (
"%s" % result.the_file
== "<GridFSProxy: hello (%s)>" % result.the_file.grid_id
)
self.assertEqual(result.the_file.read(), text)
self.assertEqual(result.the_file.content_type, content_type)
assert result.the_file.read() == text
assert result.the_file.content_type == content_type
result.the_file.delete() # Remove file from GridFS
PutFile.objects.delete()
@ -85,9 +87,9 @@ class TestFileField(MongoDBTestCase):
putfile.save()
result = PutFile.objects.first()
self.assertEqual(putfile, result)
self.assertEqual(result.the_file.read(), text)
self.assertEqual(result.the_file.content_type, content_type)
assert putfile == result
assert result.the_file.read() == text
assert result.the_file.content_type == content_type
result.the_file.delete()
def test_file_fields_stream(self):
@ -111,19 +113,19 @@ class TestFileField(MongoDBTestCase):
streamfile.save()
result = StreamFile.objects.first()
self.assertEqual(streamfile, result)
self.assertEqual(result.the_file.read(), text + more_text)
self.assertEqual(result.the_file.content_type, content_type)
assert streamfile == result
assert result.the_file.read() == text + more_text
assert result.the_file.content_type == content_type
result.the_file.seek(0)
self.assertEqual(result.the_file.tell(), 0)
self.assertEqual(result.the_file.read(len(text)), text)
self.assertEqual(result.the_file.tell(), len(text))
self.assertEqual(result.the_file.read(len(more_text)), more_text)
self.assertEqual(result.the_file.tell(), len(text + more_text))
assert result.the_file.tell() == 0
assert result.the_file.read(len(text)) == text
assert result.the_file.tell() == len(text)
assert result.the_file.read(len(more_text)) == more_text
assert result.the_file.tell() == len(text + more_text)
result.the_file.delete()
# Ensure deleted file returns None
self.assertTrue(result.the_file.read() is None)
assert result.the_file.read() is None
def test_file_fields_stream_after_none(self):
"""Ensure that a file field can be written to after it has been saved as
@ -137,7 +139,6 @@ class TestFileField(MongoDBTestCase):
text = six.b("Hello, World!")
more_text = six.b("Foo Bar")
content_type = "text/plain"
streamfile = StreamFile()
streamfile.save()
@ -148,19 +149,19 @@ class TestFileField(MongoDBTestCase):
streamfile.save()
result = StreamFile.objects.first()
self.assertEqual(streamfile, result)
self.assertEqual(result.the_file.read(), text + more_text)
# self.assertEqual(result.the_file.content_type, content_type)
assert streamfile == result
assert result.the_file.read() == text + more_text
# assert result.the_file.content_type == content_type
result.the_file.seek(0)
self.assertEqual(result.the_file.tell(), 0)
self.assertEqual(result.the_file.read(len(text)), text)
self.assertEqual(result.the_file.tell(), len(text))
self.assertEqual(result.the_file.read(len(more_text)), more_text)
self.assertEqual(result.the_file.tell(), len(text + more_text))
assert result.the_file.tell() == 0
assert result.the_file.read(len(text)) == text
assert result.the_file.tell() == len(text)
assert result.the_file.read(len(more_text)) == more_text
assert result.the_file.tell() == len(text + more_text)
result.the_file.delete()
# Ensure deleted file returns None
self.assertTrue(result.the_file.read() is None)
assert result.the_file.read() is None
def test_file_fields_set(self):
class SetFile(Document):
@ -176,16 +177,16 @@ class TestFileField(MongoDBTestCase):
setfile.save()
result = SetFile.objects.first()
self.assertEqual(setfile, result)
self.assertEqual(result.the_file.read(), text)
assert setfile == result
assert result.the_file.read() == text
# Try replacing file with new one
result.the_file.replace(more_text)
result.save()
result = SetFile.objects.first()
self.assertEqual(setfile, result)
self.assertEqual(result.the_file.read(), more_text)
assert setfile == result
assert result.the_file.read() == more_text
result.the_file.delete()
def test_file_field_no_default(self):
@ -205,28 +206,28 @@ class TestFileField(MongoDBTestCase):
doc_b = GridDocument.objects.with_id(doc_a.id)
doc_b.the_file.replace(f, filename="doc_b")
doc_b.save()
self.assertNotEqual(doc_b.the_file.grid_id, None)
assert doc_b.the_file.grid_id is not None
# Test it matches
doc_c = GridDocument.objects.with_id(doc_b.id)
self.assertEqual(doc_b.the_file.grid_id, doc_c.the_file.grid_id)
assert doc_b.the_file.grid_id == doc_c.the_file.grid_id
# Test with default
doc_d = GridDocument(the_file=six.b(""))
doc_d.save()
doc_e = GridDocument.objects.with_id(doc_d.id)
self.assertEqual(doc_d.the_file.grid_id, doc_e.the_file.grid_id)
assert doc_d.the_file.grid_id == doc_e.the_file.grid_id
doc_e.the_file.replace(f, filename="doc_e")
doc_e.save()
doc_f = GridDocument.objects.with_id(doc_e.id)
self.assertEqual(doc_e.the_file.grid_id, doc_f.the_file.grid_id)
assert doc_e.the_file.grid_id == doc_f.the_file.grid_id
db = GridDocument._get_db()
grid_fs = gridfs.GridFS(db)
self.assertEqual(["doc_b", "doc_e"], grid_fs.list())
assert ["doc_b", "doc_e"] == grid_fs.list()
def test_file_uniqueness(self):
"""Ensure that each instance of a FileField is unique
@ -246,8 +247,8 @@ class TestFileField(MongoDBTestCase):
test_file_dupe = TestFile()
data = test_file_dupe.the_file.read() # Should be None
self.assertNotEqual(test_file.name, test_file_dupe.name)
self.assertNotEqual(test_file.the_file.read(), data)
assert test_file.name != test_file_dupe.name
assert test_file.the_file.read() != data
TestFile.drop_collection()
@ -268,8 +269,8 @@ class TestFileField(MongoDBTestCase):
marmot.save()
marmot = Animal.objects.get()
self.assertEqual(marmot.photo.content_type, "image/jpeg")
self.assertEqual(marmot.photo.foo, "bar")
assert marmot.photo.content_type == "image/jpeg"
assert marmot.photo.foo == "bar"
def test_file_reassigning(self):
class TestFile(Document):
@ -278,12 +279,12 @@ class TestFileField(MongoDBTestCase):
TestFile.drop_collection()
test_file = TestFile(the_file=get_file(TEST_IMAGE_PATH)).save()
self.assertEqual(test_file.the_file.get().length, 8313)
assert test_file.the_file.get().length == 8313
test_file = TestFile.objects.first()
test_file.the_file = get_file(TEST_IMAGE2_PATH)
test_file.save()
self.assertEqual(test_file.the_file.get().length, 4971)
assert test_file.the_file.get().length == 4971
def test_file_boolean(self):
"""Ensure that a boolean test of a FileField indicates its presence
@ -295,13 +296,13 @@ class TestFileField(MongoDBTestCase):
TestFile.drop_collection()
test_file = TestFile()
self.assertFalse(bool(test_file.the_file))
assert not bool(test_file.the_file)
test_file.the_file.put(six.b("Hello, World!"), content_type="text/plain")
test_file.save()
self.assertTrue(bool(test_file.the_file))
assert bool(test_file.the_file)
test_file = TestFile.objects.first()
self.assertEqual(test_file.the_file.content_type, "text/plain")
assert test_file.the_file.content_type == "text/plain"
def test_file_cmp(self):
"""Test comparing against other types"""
@ -310,7 +311,7 @@ class TestFileField(MongoDBTestCase):
the_file = FileField()
test_file = TestFile()
self.assertNotIn(test_file.the_file, [{"test": 1}])
assert test_file.the_file not in [{"test": 1}]
def test_file_disk_space(self):
""" Test disk space usage when we delete/replace a file """
@ -330,16 +331,16 @@ class TestFileField(MongoDBTestCase):
files = db.fs.files.find()
chunks = db.fs.chunks.find()
self.assertEqual(len(list(files)), 1)
self.assertEqual(len(list(chunks)), 1)
assert len(list(files)) == 1
assert len(list(chunks)) == 1
# Deleting the docoument should delete the files
testfile.delete()
files = db.fs.files.find()
chunks = db.fs.chunks.find()
self.assertEqual(len(list(files)), 0)
self.assertEqual(len(list(chunks)), 0)
assert len(list(files)) == 0
assert len(list(chunks)) == 0
# Test case where we don't store a file in the first place
testfile = TestFile()
@ -347,15 +348,15 @@ class TestFileField(MongoDBTestCase):
files = db.fs.files.find()
chunks = db.fs.chunks.find()
self.assertEqual(len(list(files)), 0)
self.assertEqual(len(list(chunks)), 0)
assert len(list(files)) == 0
assert len(list(chunks)) == 0
testfile.delete()
files = db.fs.files.find()
chunks = db.fs.chunks.find()
self.assertEqual(len(list(files)), 0)
self.assertEqual(len(list(chunks)), 0)
assert len(list(files)) == 0
assert len(list(chunks)) == 0
# Test case where we overwrite the file
testfile = TestFile()
@ -368,20 +369,18 @@ class TestFileField(MongoDBTestCase):
files = db.fs.files.find()
chunks = db.fs.chunks.find()
self.assertEqual(len(list(files)), 1)
self.assertEqual(len(list(chunks)), 1)
assert len(list(files)) == 1
assert len(list(chunks)) == 1
testfile.delete()
files = db.fs.files.find()
chunks = db.fs.chunks.find()
self.assertEqual(len(list(files)), 0)
self.assertEqual(len(list(chunks)), 0)
assert len(list(files)) == 0
assert len(list(chunks)) == 0
@require_pil
def test_image_field(self):
if not HAS_PIL:
raise SkipTest("PIL not installed")
class TestImage(Document):
image = ImageField()
@ -396,9 +395,7 @@ class TestFileField(MongoDBTestCase):
t.image.put(f)
self.fail("Should have raised an invalidation error")
except ValidationError as e:
self.assertEqual(
"%s" % e, "Invalid image: cannot identify image file %s" % f
)
assert "%s" % e == "Invalid image: cannot identify image file %s" % f
t = TestImage()
t.image.put(get_file(TEST_IMAGE_PATH))
@ -406,35 +403,31 @@ class TestFileField(MongoDBTestCase):
t = TestImage.objects.first()
self.assertEqual(t.image.format, "PNG")
assert t.image.format == "PNG"
w, h = t.image.size
self.assertEqual(w, 371)
self.assertEqual(h, 76)
assert w == 371
assert h == 76
t.image.delete()
@require_pil
def test_image_field_reassigning(self):
if not HAS_PIL:
raise SkipTest("PIL not installed")
class TestFile(Document):
the_file = ImageField()
TestFile.drop_collection()
test_file = TestFile(the_file=get_file(TEST_IMAGE_PATH)).save()
self.assertEqual(test_file.the_file.size, (371, 76))
assert test_file.the_file.size == (371, 76)
test_file = TestFile.objects.first()
test_file.the_file = get_file(TEST_IMAGE2_PATH)
test_file.save()
self.assertEqual(test_file.the_file.size, (45, 101))
assert test_file.the_file.size == (45, 101)
@require_pil
def test_image_field_resize(self):
if not HAS_PIL:
raise SkipTest("PIL not installed")
class TestImage(Document):
image = ImageField(size=(185, 37))
@ -446,18 +439,16 @@ class TestFileField(MongoDBTestCase):
t = TestImage.objects.first()
self.assertEqual(t.image.format, "PNG")
assert t.image.format == "PNG"
w, h = t.image.size
self.assertEqual(w, 185)
self.assertEqual(h, 37)
assert w == 185
assert h == 37
t.image.delete()
@require_pil
def test_image_field_resize_force(self):
if not HAS_PIL:
raise SkipTest("PIL not installed")
class TestImage(Document):
image = ImageField(size=(185, 37, True))
@ -469,18 +460,16 @@ class TestFileField(MongoDBTestCase):
t = TestImage.objects.first()
self.assertEqual(t.image.format, "PNG")
assert t.image.format == "PNG"
w, h = t.image.size
self.assertEqual(w, 185)
self.assertEqual(h, 37)
assert w == 185
assert h == 37
t.image.delete()
@require_pil
def test_image_field_thumbnail(self):
if not HAS_PIL:
raise SkipTest("PIL not installed")
class TestImage(Document):
image = ImageField(thumbnail_size=(92, 18))
@ -492,9 +481,9 @@ class TestFileField(MongoDBTestCase):
t = TestImage.objects.first()
self.assertEqual(t.image.thumbnail.format, "PNG")
self.assertEqual(t.image.thumbnail.width, 92)
self.assertEqual(t.image.thumbnail.height, 18)
assert t.image.thumbnail.format == "PNG"
assert t.image.thumbnail.width == 92
assert t.image.thumbnail.height == 18
t.image.delete()
@ -518,17 +507,17 @@ class TestFileField(MongoDBTestCase):
test_file.save()
data = get_db("test_files").macumba.files.find_one()
self.assertEqual(data.get("name"), "hello.txt")
assert data.get("name") == "hello.txt"
test_file = TestFile.objects.first()
self.assertEqual(test_file.the_file.read(), six.b("Hello, World!"))
assert test_file.the_file.read() == six.b("Hello, World!")
test_file = TestFile.objects.first()
test_file.the_file = six.b("HELLO, WORLD!")
test_file.save()
test_file = TestFile.objects.first()
self.assertEqual(test_file.the_file.read(), six.b("HELLO, WORLD!"))
assert test_file.the_file.read() == six.b("HELLO, WORLD!")
def test_copyable(self):
class PutFile(Document):
@ -546,14 +535,11 @@ class TestFileField(MongoDBTestCase):
class TestFile(Document):
name = StringField()
self.assertEqual(putfile, copy.copy(putfile))
self.assertEqual(putfile, copy.deepcopy(putfile))
assert putfile == copy.copy(putfile)
assert putfile == copy.deepcopy(putfile)
@require_pil
def test_get_image_by_grid_id(self):
if not HAS_PIL:
raise SkipTest("PIL not installed")
class TestImage(Document):
image1 = ImageField()
@ -569,9 +555,7 @@ class TestFileField(MongoDBTestCase):
test = TestImage.objects.first()
grid_id = test.image1.grid_id
self.assertEqual(
1, TestImage.objects(Q(image1=grid_id) or Q(image2=grid_id)).count()
)
assert 1 == TestImage.objects(Q(image1=grid_id) or Q(image2=grid_id)).count()
def test_complex_field_filefield(self):
"""Ensure you can add meta data to file"""
@ -593,9 +577,9 @@ class TestFileField(MongoDBTestCase):
marmot.save()
marmot = Animal.objects.get()
self.assertEqual(marmot.photos[0].content_type, "image/jpeg")
self.assertEqual(marmot.photos[0].foo, "bar")
self.assertEqual(marmot.photos[0].get().length, 8313)
assert marmot.photos[0].content_type == "image/jpeg"
assert marmot.photos[0].foo == "bar"
assert marmot.photos[0].get().length == 8313
if __name__ == "__main__":

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import pytest
import six
from mongoengine import *
@ -16,8 +17,8 @@ class TestFloatField(MongoDBTestCase):
TestDocument(float_fld=None).save()
TestDocument(float_fld=1).save()
self.assertEqual(1, TestDocument.objects(float_fld__ne=None).count())
self.assertEqual(1, TestDocument.objects(float_fld__ne=1).count())
assert 1 == TestDocument.objects(float_fld__ne=None).count()
assert 1 == TestDocument.objects(float_fld__ne=1).count()
def test_validation(self):
"""Ensure that invalid values cannot be assigned to float fields.
@ -34,16 +35,20 @@ class TestFloatField(MongoDBTestCase):
person.validate()
person.height = "2.0"
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.height = 0.01
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.height = 4.0
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person_2 = Person(height="something invalid")
self.assertRaises(ValidationError, person_2.validate)
with pytest.raises(ValidationError):
person_2.validate()
big_person = BigPerson()
@ -55,4 +60,5 @@ class TestFloatField(MongoDBTestCase):
big_person.validate()
big_person.height = 2 ** 100000 # Too big for a float value
self.assertRaises(ValidationError, big_person.validate)
with pytest.raises(ValidationError):
big_person.validate()

View File

@ -11,7 +11,7 @@ class TestGeoField(MongoDBTestCase):
Cls(loc=loc).validate()
self.fail("Should not validate the location {0}".format(loc))
except ValidationError as e:
self.assertEqual(expected, e.to_dict()["loc"])
assert expected == e.to_dict()["loc"]
def test_geopoint_validation(self):
class Location(Document):
@ -299,7 +299,7 @@ class TestGeoField(MongoDBTestCase):
location = GeoPointField()
geo_indicies = Event._geo_indices()
self.assertEqual(geo_indicies, [{"fields": [("location", "2d")]}])
assert geo_indicies == [{"fields": [("location", "2d")]}]
def test_geopoint_embedded_indexes(self):
"""Ensure that indexes are created automatically for GeoPointFields on
@ -315,7 +315,7 @@ class TestGeoField(MongoDBTestCase):
venue = EmbeddedDocumentField(Venue)
geo_indicies = Event._geo_indices()
self.assertEqual(geo_indicies, [{"fields": [("venue.location", "2d")]}])
assert geo_indicies == [{"fields": [("venue.location", "2d")]}]
def test_indexes_2dsphere(self):
"""Ensure that indexes are created automatically for GeoPointFields.
@ -328,9 +328,9 @@ class TestGeoField(MongoDBTestCase):
polygon = PolygonField()
geo_indicies = Event._geo_indices()
self.assertIn({"fields": [("line", "2dsphere")]}, geo_indicies)
self.assertIn({"fields": [("polygon", "2dsphere")]}, geo_indicies)
self.assertIn({"fields": [("point", "2dsphere")]}, geo_indicies)
assert {"fields": [("line", "2dsphere")]} in geo_indicies
assert {"fields": [("polygon", "2dsphere")]} in geo_indicies
assert {"fields": [("point", "2dsphere")]} in geo_indicies
def test_indexes_2dsphere_embedded(self):
"""Ensure that indexes are created automatically for GeoPointFields.
@ -347,9 +347,9 @@ class TestGeoField(MongoDBTestCase):
venue = EmbeddedDocumentField(Venue)
geo_indicies = Event._geo_indices()
self.assertIn({"fields": [("venue.line", "2dsphere")]}, geo_indicies)
self.assertIn({"fields": [("venue.polygon", "2dsphere")]}, geo_indicies)
self.assertIn({"fields": [("venue.point", "2dsphere")]}, geo_indicies)
assert {"fields": [("venue.line", "2dsphere")]} in geo_indicies
assert {"fields": [("venue.polygon", "2dsphere")]} in geo_indicies
assert {"fields": [("venue.point", "2dsphere")]} in geo_indicies
def test_geo_indexes_recursion(self):
class Location(Document):
@ -365,12 +365,12 @@ class TestGeoField(MongoDBTestCase):
Parent(name="Berlin").save()
info = Parent._get_collection().index_information()
self.assertNotIn("location_2d", info)
assert "location_2d" not in info
info = Location._get_collection().index_information()
self.assertIn("location_2d", info)
assert "location_2d" in info
self.assertEqual(len(Parent._geo_indices()), 0)
self.assertEqual(len(Location._geo_indices()), 1)
assert len(Parent._geo_indices()) == 0
assert len(Location._geo_indices()) == 1
def test_geo_indexes_auto_index(self):
@ -381,16 +381,16 @@ class TestGeoField(MongoDBTestCase):
meta = {"indexes": [[("location", "2dsphere"), ("datetime", 1)]]}
self.assertEqual([], Log._geo_indices())
assert [] == Log._geo_indices()
Log.drop_collection()
Log.ensure_indexes()
info = Log._get_collection().index_information()
self.assertEqual(
info["location_2dsphere_datetime_1"]["key"],
[("location", "2dsphere"), ("datetime", 1)],
)
assert info["location_2dsphere_datetime_1"]["key"] == [
("location", "2dsphere"),
("datetime", 1),
]
# Test listing explicitly
class Log(Document):
@ -401,16 +401,16 @@ class TestGeoField(MongoDBTestCase):
"indexes": [{"fields": [("location", "2dsphere"), ("datetime", 1)]}]
}
self.assertEqual([], Log._geo_indices())
assert [] == Log._geo_indices()
Log.drop_collection()
Log.ensure_indexes()
info = Log._get_collection().index_information()
self.assertEqual(
info["location_2dsphere_datetime_1"]["key"],
[("location", "2dsphere"), ("datetime", 1)],
)
assert info["location_2dsphere_datetime_1"]["key"] == [
("location", "2dsphere"),
("datetime", 1),
]
if __name__ == "__main__":

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -23,11 +25,14 @@ class TestIntField(MongoDBTestCase):
person.validate()
person.age = -1
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.age = 120
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
person.age = "ten"
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
def test_ne_operator(self):
class TestDocument(Document):
@ -38,5 +43,5 @@ class TestIntField(MongoDBTestCase):
TestDocument(int_fld=None).save()
TestDocument(int_fld=1).save()
self.assertEqual(1, TestDocument.objects(int_fld__ne=None).count())
self.assertEqual(1, TestDocument.objects(int_fld__ne=1).count())
assert 1 == TestDocument.objects(int_fld__ne=None).count()
assert 1 == TestDocument.objects(int_fld__ne=1).count()

View File

@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
from bson import DBRef, ObjectId
import pytest
from mongoengine import *
from mongoengine.base import LazyReference
@ -11,7 +12,8 @@ class TestLazyReferenceField(MongoDBTestCase):
def test_lazy_reference_config(self):
# Make sure ReferenceField only accepts a document class or a string
# with a document class name.
self.assertRaises(ValidationError, LazyReferenceField, EmbeddedDocument)
with pytest.raises(ValidationError):
LazyReferenceField(EmbeddedDocument)
def test___repr__(self):
class Animal(Document):
@ -25,7 +27,7 @@ class TestLazyReferenceField(MongoDBTestCase):
animal = Animal()
oc = Ocurrence(animal=animal)
self.assertIn("LazyReference", repr(oc.animal))
assert "LazyReference" in repr(oc.animal)
def test___getattr___unknown_attr_raises_attribute_error(self):
class Animal(Document):
@ -39,7 +41,7 @@ class TestLazyReferenceField(MongoDBTestCase):
animal = Animal().save()
oc = Ocurrence(animal=animal)
with self.assertRaises(AttributeError):
with pytest.raises(AttributeError):
oc.animal.not_exist
def test_lazy_reference_simple(self):
@ -57,19 +59,19 @@ class TestLazyReferenceField(MongoDBTestCase):
animal = Animal(name="Leopard", tag="heavy").save()
Ocurrence(person="test", animal=animal).save()
p = Ocurrence.objects.get()
self.assertIsInstance(p.animal, LazyReference)
assert isinstance(p.animal, LazyReference)
fetched_animal = p.animal.fetch()
self.assertEqual(fetched_animal, animal)
assert fetched_animal == animal
# `fetch` keep cache on referenced document by default...
animal.tag = "not so heavy"
animal.save()
double_fetch = p.animal.fetch()
self.assertIs(fetched_animal, double_fetch)
self.assertEqual(double_fetch.tag, "heavy")
assert fetched_animal is double_fetch
assert double_fetch.tag == "heavy"
# ...unless specified otherwise
fetch_force = p.animal.fetch(force=True)
self.assertIsNot(fetch_force, fetched_animal)
self.assertEqual(fetch_force.tag, "not so heavy")
assert fetch_force is not fetched_animal
assert fetch_force.tag == "not so heavy"
def test_lazy_reference_fetch_invalid_ref(self):
class Animal(Document):
@ -87,8 +89,8 @@ class TestLazyReferenceField(MongoDBTestCase):
Ocurrence(person="test", animal=animal).save()
animal.delete()
p = Ocurrence.objects.get()
self.assertIsInstance(p.animal, LazyReference)
with self.assertRaises(DoesNotExist):
assert isinstance(p.animal, LazyReference)
with pytest.raises(DoesNotExist):
p.animal.fetch()
def test_lazy_reference_set(self):
@ -122,7 +124,7 @@ class TestLazyReferenceField(MongoDBTestCase):
):
p = Ocurrence(person="test", animal=ref).save()
p.reload()
self.assertIsInstance(p.animal, LazyReference)
assert isinstance(p.animal, LazyReference)
p.animal.fetch()
def test_lazy_reference_bad_set(self):
@ -149,7 +151,7 @@ class TestLazyReferenceField(MongoDBTestCase):
DBRef(baddoc._get_collection_name(), animal.pk),
LazyReference(BadDoc, animal.pk),
):
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
p = Ocurrence(person="test", animal=bad).save()
def test_lazy_reference_query_conversion(self):
@ -179,14 +181,14 @@ class TestLazyReferenceField(MongoDBTestCase):
post2.save()
post = BlogPost.objects(author=m1).first()
self.assertEqual(post.id, post1.id)
assert post.id == post1.id
post = BlogPost.objects(author=m2).first()
self.assertEqual(post.id, post2.id)
assert post.id == post2.id
# Same thing by passing a LazyReference instance
post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first()
self.assertEqual(post.id, post2.id)
assert post.id == post2.id
def test_lazy_reference_query_conversion_dbref(self):
"""Ensure that LazyReferenceFields can be queried using objects and values
@ -215,14 +217,14 @@ class TestLazyReferenceField(MongoDBTestCase):
post2.save()
post = BlogPost.objects(author=m1).first()
self.assertEqual(post.id, post1.id)
assert post.id == post1.id
post = BlogPost.objects(author=m2).first()
self.assertEqual(post.id, post2.id)
assert post.id == post2.id
# Same thing by passing a LazyReference instance
post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first()
self.assertEqual(post.id, post2.id)
assert post.id == post2.id
def test_lazy_reference_passthrough(self):
class Animal(Document):
@ -239,20 +241,20 @@ class TestLazyReferenceField(MongoDBTestCase):
animal = Animal(name="Leopard", tag="heavy").save()
Ocurrence(animal=animal, animal_passthrough=animal).save()
p = Ocurrence.objects.get()
self.assertIsInstance(p.animal, LazyReference)
with self.assertRaises(KeyError):
assert isinstance(p.animal, LazyReference)
with pytest.raises(KeyError):
p.animal["name"]
with self.assertRaises(AttributeError):
with pytest.raises(AttributeError):
p.animal.name
self.assertEqual(p.animal.pk, animal.pk)
assert p.animal.pk == animal.pk
self.assertEqual(p.animal_passthrough.name, "Leopard")
self.assertEqual(p.animal_passthrough["name"], "Leopard")
assert p.animal_passthrough.name == "Leopard"
assert p.animal_passthrough["name"] == "Leopard"
# Should not be able to access referenced document's methods
with self.assertRaises(AttributeError):
with pytest.raises(AttributeError):
p.animal.save
with self.assertRaises(KeyError):
with pytest.raises(KeyError):
p.animal["save"]
def test_lazy_reference_not_set(self):
@ -269,7 +271,7 @@ class TestLazyReferenceField(MongoDBTestCase):
Ocurrence(person="foo").save()
p = Ocurrence.objects.get()
self.assertIs(p.animal, None)
assert p.animal is None
def test_lazy_reference_equality(self):
class Animal(Document):
@ -280,12 +282,12 @@ class TestLazyReferenceField(MongoDBTestCase):
animal = Animal(name="Leopard", tag="heavy").save()
animalref = LazyReference(Animal, animal.pk)
self.assertEqual(animal, animalref)
self.assertEqual(animalref, animal)
assert animal == animalref
assert animalref == animal
other_animalref = LazyReference(Animal, ObjectId("54495ad94c934721ede76f90"))
self.assertNotEqual(animal, other_animalref)
self.assertNotEqual(other_animalref, animal)
assert animal != other_animalref
assert other_animalref != animal
def test_lazy_reference_embedded(self):
class Animal(Document):
@ -308,12 +310,12 @@ class TestLazyReferenceField(MongoDBTestCase):
animal2 = Animal(name="cheeta").save()
def check_fields_type(occ):
self.assertIsInstance(occ.direct, LazyReference)
assert isinstance(occ.direct, LazyReference)
for elem in occ.in_list:
self.assertIsInstance(elem, LazyReference)
self.assertIsInstance(occ.in_embedded.direct, LazyReference)
assert isinstance(elem, LazyReference)
assert isinstance(occ.in_embedded.direct, LazyReference)
for elem in occ.in_embedded.in_list:
self.assertIsInstance(elem, LazyReference)
assert isinstance(elem, LazyReference)
occ = Ocurrence(
in_list=[animal1, animal2],
@ -346,19 +348,19 @@ class TestGenericLazyReferenceField(MongoDBTestCase):
animal = Animal(name="Leopard", tag="heavy").save()
Ocurrence(person="test", animal=animal).save()
p = Ocurrence.objects.get()
self.assertIsInstance(p.animal, LazyReference)
assert isinstance(p.animal, LazyReference)
fetched_animal = p.animal.fetch()
self.assertEqual(fetched_animal, animal)
assert fetched_animal == animal
# `fetch` keep cache on referenced document by default...
animal.tag = "not so heavy"
animal.save()
double_fetch = p.animal.fetch()
self.assertIs(fetched_animal, double_fetch)
self.assertEqual(double_fetch.tag, "heavy")
assert fetched_animal is double_fetch
assert double_fetch.tag == "heavy"
# ...unless specified otherwise
fetch_force = p.animal.fetch(force=True)
self.assertIsNot(fetch_force, fetched_animal)
self.assertEqual(fetch_force.tag, "not so heavy")
assert fetch_force is not fetched_animal
assert fetch_force.tag == "not so heavy"
def test_generic_lazy_reference_choices(self):
class Animal(Document):
@ -385,13 +387,13 @@ class TestGenericLazyReferenceField(MongoDBTestCase):
occ_animal = Ocurrence(living_thing=animal, thing=animal).save()
occ_vegetal = Ocurrence(living_thing=vegetal, thing=vegetal).save()
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
Ocurrence(living_thing=mineral).save()
occ = Ocurrence.objects.get(living_thing=animal)
self.assertEqual(occ, occ_animal)
self.assertIsInstance(occ.thing, LazyReference)
self.assertIsInstance(occ.living_thing, LazyReference)
assert occ == occ_animal
assert isinstance(occ.thing, LazyReference)
assert isinstance(occ.living_thing, LazyReference)
occ.thing = vegetal
occ.living_thing = vegetal
@ -399,7 +401,7 @@ class TestGenericLazyReferenceField(MongoDBTestCase):
occ.thing = mineral
occ.living_thing = mineral
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
occ.save()
def test_generic_lazy_reference_set(self):
@ -434,7 +436,7 @@ class TestGenericLazyReferenceField(MongoDBTestCase):
):
p = Ocurrence(person="test", animal=ref).save()
p.reload()
self.assertIsInstance(p.animal, (LazyReference, Document))
assert isinstance(p.animal, (LazyReference, Document))
p.animal.fetch()
def test_generic_lazy_reference_bad_set(self):
@ -455,7 +457,7 @@ class TestGenericLazyReferenceField(MongoDBTestCase):
animal = Animal(name="Leopard", tag="heavy").save()
baddoc = BadDoc().save()
for bad in (42, "foo", baddoc, LazyReference(BadDoc, animal.pk)):
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
p = Ocurrence(person="test", animal=bad).save()
def test_generic_lazy_reference_query_conversion(self):
@ -481,14 +483,14 @@ class TestGenericLazyReferenceField(MongoDBTestCase):
post2.save()
post = BlogPost.objects(author=m1).first()
self.assertEqual(post.id, post1.id)
assert post.id == post1.id
post = BlogPost.objects(author=m2).first()
self.assertEqual(post.id, post2.id)
assert post.id == post2.id
# Same thing by passing a LazyReference instance
post = BlogPost.objects(author=LazyReference(Member, m2.pk)).first()
self.assertEqual(post.id, post2.id)
assert post.id == post2.id
def test_generic_lazy_reference_not_set(self):
class Animal(Document):
@ -504,7 +506,7 @@ class TestGenericLazyReferenceField(MongoDBTestCase):
Ocurrence(person="foo").save()
p = Ocurrence.objects.get()
self.assertIs(p.animal, None)
assert p.animal is None
def test_generic_lazy_reference_accepts_string_instead_of_class(self):
class Animal(Document):
@ -521,7 +523,7 @@ class TestGenericLazyReferenceField(MongoDBTestCase):
animal = Animal().save()
Ocurrence(animal=animal).save()
p = Ocurrence.objects.get()
self.assertEqual(p.animal, animal)
assert p.animal == animal
def test_generic_lazy_reference_embedded(self):
class Animal(Document):
@ -544,12 +546,12 @@ class TestGenericLazyReferenceField(MongoDBTestCase):
animal2 = Animal(name="cheeta").save()
def check_fields_type(occ):
self.assertIsInstance(occ.direct, LazyReference)
assert isinstance(occ.direct, LazyReference)
for elem in occ.in_list:
self.assertIsInstance(elem, LazyReference)
self.assertIsInstance(occ.in_embedded.direct, LazyReference)
assert isinstance(elem, LazyReference)
assert isinstance(occ.in_embedded.direct, LazyReference)
for elem in occ.in_embedded.in_list:
self.assertIsInstance(elem, LazyReference)
assert isinstance(elem, LazyReference)
occ = Ocurrence(
in_list=[animal1, animal2],

View File

@ -1,4 +1,5 @@
# -*- coding: utf-8 -*-
import pytest
import six
try:
@ -24,10 +25,10 @@ class TestLongField(MongoDBTestCase):
doc = TestLongFieldConsideredAsInt64(some_long=42).save()
db = get_db()
self.assertIsInstance(
assert isinstance(
db.test_long_field_considered_as_int64.find()[0]["some_long"], Int64
)
self.assertIsInstance(doc.some_long, six.integer_types)
assert isinstance(doc.some_long, six.integer_types)
def test_long_validation(self):
"""Ensure that invalid values cannot be assigned to long fields.
@ -41,11 +42,14 @@ class TestLongField(MongoDBTestCase):
doc.validate()
doc.value = -1
self.assertRaises(ValidationError, doc.validate)
with pytest.raises(ValidationError):
doc.validate()
doc.value = 120
self.assertRaises(ValidationError, doc.validate)
with pytest.raises(ValidationError):
doc.validate()
doc.value = "ten"
self.assertRaises(ValidationError, doc.validate)
with pytest.raises(ValidationError):
doc.validate()
def test_long_ne_operator(self):
class TestDocument(Document):
@ -56,4 +60,4 @@ class TestLongField(MongoDBTestCase):
TestDocument(long_fld=None).save()
TestDocument(long_fld=1).save()
self.assertEqual(1, TestDocument.objects(long_fld__ne=None).count())
assert 1 == TestDocument.objects(long_fld__ne=None).count()

View File

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
import datetime
from mongoengine import *
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -19,11 +20,11 @@ class TestMapField(MongoDBTestCase):
e.mapping["someint"] = 1
e.save()
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
e.mapping["somestring"] = "abc"
e.save()
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
class NoDeclaredType(Document):
mapping = MapField()
@ -51,10 +52,10 @@ class TestMapField(MongoDBTestCase):
e.save()
e2 = Extensible.objects.get(id=e.id)
self.assertIsInstance(e2.mapping["somestring"], StringSetting)
self.assertIsInstance(e2.mapping["someint"], IntegerSetting)
assert isinstance(e2.mapping["somestring"], StringSetting)
assert isinstance(e2.mapping["someint"], IntegerSetting)
with self.assertRaises(ValidationError):
with pytest.raises(ValidationError):
e.mapping["someint"] = 123
e.save()
@ -74,9 +75,9 @@ class TestMapField(MongoDBTestCase):
Test.objects.update_one(inc__my_map__DICTIONARY_KEY__number=1)
test = Test.objects.get()
self.assertEqual(test.my_map["DICTIONARY_KEY"].number, 2)
assert test.my_map["DICTIONARY_KEY"].number == 2
doc = self.db.test.find_one()
self.assertEqual(doc["x"]["DICTIONARY_KEY"]["i"], 2)
assert doc["x"]["DICTIONARY_KEY"]["i"] == 2
def test_mapfield_numerical_index(self):
"""Ensure that MapField accept numeric strings as indexes."""
@ -116,13 +117,13 @@ class TestMapField(MongoDBTestCase):
actions={"friends": Action(operation="drink", object="beer")},
).save()
self.assertEqual(1, Log.objects(visited__friends__exists=True).count())
assert 1 == Log.objects(visited__friends__exists=True).count()
self.assertEqual(
1,
Log.objects(
assert (
1
== Log.objects(
actions__friends__operation="drink", actions__friends__object="beer"
).count(),
).count()
)
def test_map_field_unicode(self):
@ -139,7 +140,7 @@ class TestMapField(MongoDBTestCase):
tree.save()
self.assertEqual(
BlogPost.objects.get(id=tree.id).info_dict[u"éééé"].description,
u"VALUE: éééé",
assert (
BlogPost.objects.get(id=tree.id).info_dict[u"éééé"].description
== u"VALUE: éééé"
)

View File

@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
from bson import SON, DBRef
from bson import DBRef, SON
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -24,19 +24,22 @@ class TestReferenceField(MongoDBTestCase):
# Make sure ReferenceField only accepts a document class or a string
# with a document class name.
self.assertRaises(ValidationError, ReferenceField, EmbeddedDocument)
with pytest.raises(ValidationError):
ReferenceField(EmbeddedDocument)
user = User(name="Test User")
# Ensure that the referenced object must have been saved
post1 = BlogPost(content="Chips and gravy taste good.")
post1.author = user
self.assertRaises(ValidationError, post1.save)
with pytest.raises(ValidationError):
post1.save()
# Check that an invalid object type cannot be used
post2 = BlogPost(content="Chips and chilli taste good.")
post1.author = post2
self.assertRaises(ValidationError, post1.validate)
with pytest.raises(ValidationError):
post1.validate()
# Ensure ObjectID's are accepted as references
user_object_id = user.pk
@ -52,22 +55,8 @@ class TestReferenceField(MongoDBTestCase):
# Make sure referencing a saved document of the *wrong* type fails
post2.save()
post1.author = post2
self.assertRaises(ValidationError, post1.validate)
def test_objectid_reference_fields(self):
"""Make sure storing Object ID references works."""
class Person(Document):
name = StringField()
parent = ReferenceField("self")
Person.drop_collection()
p1 = Person(name="John").save()
Person(name="Ross", parent=p1.pk).save()
p = Person.objects.get(name="Ross")
self.assertEqual(p.parent, p1)
with pytest.raises(ValidationError):
post1.validate()
def test_dbref_reference_fields(self):
"""Make sure storing references as bson.dbref.DBRef works."""
@ -81,13 +70,12 @@ class TestReferenceField(MongoDBTestCase):
p1 = Person(name="John").save()
Person(name="Ross", parent=p1).save()
self.assertEqual(
Person._get_collection().find_one({"name": "Ross"})["parent"],
DBRef("person", p1.pk),
assert Person._get_collection().find_one({"name": "Ross"})["parent"] == DBRef(
"person", p1.pk
)
p = Person.objects.get(name="Ross")
self.assertEqual(p.parent, p1)
assert p.parent == p1
def test_dbref_to_mongo(self):
"""Make sure that calling to_mongo on a ReferenceField which
@ -100,9 +88,7 @@ class TestReferenceField(MongoDBTestCase):
parent = ReferenceField("self", dbref=False)
p = Person(name="Steve", parent=DBRef("person", "abcdefghijklmnop"))
self.assertEqual(
p.to_mongo(), SON([("name", u"Steve"), ("parent", "abcdefghijklmnop")])
)
assert p.to_mongo() == SON([("name", u"Steve"), ("parent", "abcdefghijklmnop")])
def test_objectid_reference_fields(self):
class Person(Document):
@ -116,10 +102,10 @@ class TestReferenceField(MongoDBTestCase):
col = Person._get_collection()
data = col.find_one({"name": "Ross"})
self.assertEqual(data["parent"], p1.pk)
assert data["parent"] == p1.pk
p = Person.objects.get(name="Ross")
self.assertEqual(p.parent, p1)
assert p.parent == p1
def test_undefined_reference(self):
"""Ensure that ReferenceFields may reference undefined Documents.
@ -144,14 +130,14 @@ class TestReferenceField(MongoDBTestCase):
me.save()
obj = Product.objects(company=ten_gen).first()
self.assertEqual(obj, mongodb)
self.assertEqual(obj.company, ten_gen)
assert obj == mongodb
assert obj.company == ten_gen
obj = Product.objects(company=None).first()
self.assertEqual(obj, me)
assert obj == me
obj = Product.objects.get(company=None)
self.assertEqual(obj, me)
assert obj == me
def test_reference_query_conversion(self):
"""Ensure that ReferenceFields can be queried using objects and values
@ -180,10 +166,10 @@ class TestReferenceField(MongoDBTestCase):
post2.save()
post = BlogPost.objects(author=m1).first()
self.assertEqual(post.id, post1.id)
assert post.id == post1.id
post = BlogPost.objects(author=m2).first()
self.assertEqual(post.id, post2.id)
assert post.id == post2.id
def test_reference_query_conversion_dbref(self):
"""Ensure that ReferenceFields can be queried using objects and values
@ -212,7 +198,7 @@ class TestReferenceField(MongoDBTestCase):
post2.save()
post = BlogPost.objects(author=m1).first()
self.assertEqual(post.id, post1.id)
assert post.id == post1.id
post = BlogPost.objects(author=m2).first()
self.assertEqual(post.id, post2.id)
assert post.id == post2.id

View File

@ -18,17 +18,17 @@ class TestSequenceField(MongoDBTestCase):
Person(name="Person %s" % x).save()
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
ids = [i.id for i in Person.objects]
self.assertEqual(ids, range(1, 11))
assert ids == range(1, 11)
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
Person.id.set_next_value(1000)
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 1000)
assert c["next"] == 1000
def test_sequence_field_get_next_value(self):
class Person(Document):
@ -41,10 +41,10 @@ class TestSequenceField(MongoDBTestCase):
for x in range(10):
Person(name="Person %s" % x).save()
self.assertEqual(Person.id.get_next_value(), 11)
assert Person.id.get_next_value() == 11
self.db["mongoengine.counters"].drop()
self.assertEqual(Person.id.get_next_value(), 1)
assert Person.id.get_next_value() == 1
class Person(Document):
id = SequenceField(primary_key=True, value_decorator=str)
@ -56,10 +56,10 @@ class TestSequenceField(MongoDBTestCase):
for x in range(10):
Person(name="Person %s" % x).save()
self.assertEqual(Person.id.get_next_value(), "11")
assert Person.id.get_next_value() == "11"
self.db["mongoengine.counters"].drop()
self.assertEqual(Person.id.get_next_value(), "1")
assert Person.id.get_next_value() == "1"
def test_sequence_field_sequence_name(self):
class Person(Document):
@ -73,17 +73,17 @@ class TestSequenceField(MongoDBTestCase):
Person(name="Person %s" % x).save()
c = self.db["mongoengine.counters"].find_one({"_id": "jelly.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
ids = [i.id for i in Person.objects]
self.assertEqual(ids, range(1, 11))
assert ids == range(1, 11)
c = self.db["mongoengine.counters"].find_one({"_id": "jelly.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
Person.id.set_next_value(1000)
c = self.db["mongoengine.counters"].find_one({"_id": "jelly.id"})
self.assertEqual(c["next"], 1000)
assert c["next"] == 1000
def test_multiple_sequence_fields(self):
class Person(Document):
@ -98,24 +98,24 @@ class TestSequenceField(MongoDBTestCase):
Person(name="Person %s" % x).save()
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
ids = [i.id for i in Person.objects]
self.assertEqual(ids, range(1, 11))
assert ids == range(1, 11)
counters = [i.counter for i in Person.objects]
self.assertEqual(counters, range(1, 11))
assert counters == range(1, 11)
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
Person.id.set_next_value(1000)
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 1000)
assert c["next"] == 1000
Person.counter.set_next_value(999)
c = self.db["mongoengine.counters"].find_one({"_id": "person.counter"})
self.assertEqual(c["next"], 999)
assert c["next"] == 999
def test_sequence_fields_reload(self):
class Animal(Document):
@ -127,20 +127,20 @@ class TestSequenceField(MongoDBTestCase):
a = Animal(name="Boi").save()
self.assertEqual(a.counter, 1)
assert a.counter == 1
a.reload()
self.assertEqual(a.counter, 1)
assert a.counter == 1
a.counter = None
self.assertEqual(a.counter, 2)
assert a.counter == 2
a.save()
self.assertEqual(a.counter, 2)
assert a.counter == 2
a = Animal.objects.first()
self.assertEqual(a.counter, 2)
assert a.counter == 2
a.reload()
self.assertEqual(a.counter, 2)
assert a.counter == 2
def test_multiple_sequence_fields_on_docs(self):
class Animal(Document):
@ -160,22 +160,22 @@ class TestSequenceField(MongoDBTestCase):
Person(name="Person %s" % x).save()
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
c = self.db["mongoengine.counters"].find_one({"_id": "animal.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
ids = [i.id for i in Person.objects]
self.assertEqual(ids, range(1, 11))
assert ids == range(1, 11)
id = [i.id for i in Animal.objects]
self.assertEqual(id, range(1, 11))
assert id == range(1, 11)
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
c = self.db["mongoengine.counters"].find_one({"_id": "animal.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
def test_sequence_field_value_decorator(self):
class Person(Document):
@ -190,13 +190,13 @@ class TestSequenceField(MongoDBTestCase):
p.save()
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
ids = [i.id for i in Person.objects]
self.assertEqual(ids, map(str, range(1, 11)))
assert ids == map(str, range(1, 11))
c = self.db["mongoengine.counters"].find_one({"_id": "person.id"})
self.assertEqual(c["next"], 10)
assert c["next"] == 10
def test_embedded_sequence_field(self):
class Comment(EmbeddedDocument):
@ -218,10 +218,10 @@ class TestSequenceField(MongoDBTestCase):
],
).save()
c = self.db["mongoengine.counters"].find_one({"_id": "comment.id"})
self.assertEqual(c["next"], 2)
assert c["next"] == 2
post = Post.objects.first()
self.assertEqual(1, post.comments[0].id)
self.assertEqual(2, post.comments[1].id)
assert 1 == post.comments[0].id
assert 2 == post.comments[1].id
def test_inherited_sequencefield(self):
class Base(Document):
@ -241,16 +241,14 @@ class TestSequenceField(MongoDBTestCase):
foo = Foo(name="Foo")
foo.save()
self.assertTrue(
"base.counter" in self.db["mongoengine.counters"].find().distinct("_id")
)
self.assertFalse(
assert "base.counter" in self.db["mongoengine.counters"].find().distinct("_id")
assert not (
("foo.counter" or "bar.counter")
in self.db["mongoengine.counters"].find().distinct("_id")
)
self.assertNotEqual(foo.counter, bar.counter)
self.assertEqual(foo._fields["counter"].owner_document, Base)
self.assertEqual(bar._fields["counter"].owner_document, Base)
assert foo.counter != bar.counter
assert foo._fields["counter"].owner_document == Base
assert bar._fields["counter"].owner_document == Base
def test_no_inherited_sequencefield(self):
class Base(Document):
@ -269,13 +267,12 @@ class TestSequenceField(MongoDBTestCase):
foo = Foo(name="Foo")
foo.save()
self.assertFalse(
assert not (
"base.counter" in self.db["mongoengine.counters"].find().distinct("_id")
)
self.assertTrue(
("foo.counter" and "bar.counter")
in self.db["mongoengine.counters"].find().distinct("_id")
)
self.assertEqual(foo.counter, bar.counter)
self.assertEqual(foo._fields["counter"].owner_document, Foo)
self.assertEqual(bar._fields["counter"].owner_document, Bar)
assert ("foo.counter" and "bar.counter") in self.db[
"mongoengine.counters"
].find().distinct("_id")
assert foo.counter == bar.counter
assert foo._fields["counter"].owner_document == Foo
assert bar._fields["counter"].owner_document == Bar

View File

@ -1,4 +1,6 @@
# -*- coding: utf-8 -*-
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase
@ -13,7 +15,8 @@ class TestURLField(MongoDBTestCase):
link = Link()
link.url = "google"
self.assertRaises(ValidationError, link.validate)
with pytest.raises(ValidationError):
link.validate()
link.url = "http://www.google.com:8080"
link.validate()
@ -29,11 +32,11 @@ class TestURLField(MongoDBTestCase):
# TODO fix URL validation - this *IS* a valid URL
# For now we just want to make sure that the error message is correct
with self.assertRaises(ValidationError) as ctx_err:
with pytest.raises(ValidationError) as exc_info:
link.validate()
self.assertEqual(
unicode(ctx_err.exception),
u"ValidationError (Link:None) (Invalid URL: http://\u043f\u0440\u0438\u0432\u0435\u0442.com: ['url'])",
assert (
unicode(exc_info.value)
== u"ValidationError (Link:None) (Invalid URL: http://\u043f\u0440\u0438\u0432\u0435\u0442.com: ['url'])"
)
def test_url_scheme_validation(self):
@ -48,7 +51,8 @@ class TestURLField(MongoDBTestCase):
link = Link()
link.url = "ws://google.com"
self.assertRaises(ValidationError, link.validate)
with pytest.raises(ValidationError):
link.validate()
scheme_link = SchemeLink()
scheme_link.url = "ws://google.com"

View File

@ -1,8 +1,9 @@
# -*- coding: utf-8 -*-
import uuid
from mongoengine import *
import pytest
from mongoengine import *
from tests.utils import MongoDBTestCase, get_as_pymongo
@ -14,9 +15,7 @@ class TestUUIDField(MongoDBTestCase):
def test_storage(self):
uid = uuid.uuid4()
person = Person(api_key=uid).save()
self.assertEqual(
get_as_pymongo(person), {"_id": person.id, "api_key": str(uid)}
)
assert get_as_pymongo(person) == {"_id": person.id, "api_key": str(uid)}
def test_field_string(self):
"""Test UUID fields storing as String
@ -25,8 +24,8 @@ class TestUUIDField(MongoDBTestCase):
uu = uuid.uuid4()
Person(api_key=uu).save()
self.assertEqual(1, Person.objects(api_key=uu).count())
self.assertEqual(uu, Person.objects.first().api_key)
assert 1 == Person.objects(api_key=uu).count()
assert uu == Person.objects.first().api_key
person = Person()
valid = (uuid.uuid4(), uuid.uuid1())
@ -40,7 +39,8 @@ class TestUUIDField(MongoDBTestCase):
)
for api_key in invalid:
person.api_key = api_key
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()
def test_field_binary(self):
"""Test UUID fields storing as Binary object."""
@ -48,8 +48,8 @@ class TestUUIDField(MongoDBTestCase):
uu = uuid.uuid4()
Person(api_key=uu).save()
self.assertEqual(1, Person.objects(api_key=uu).count())
self.assertEqual(uu, Person.objects.first().api_key)
assert 1 == Person.objects(api_key=uu).count()
assert uu == Person.objects.first().api_key
person = Person()
valid = (uuid.uuid4(), uuid.uuid1())
@ -63,4 +63,5 @@ class TestUUIDField(MongoDBTestCase):
)
for api_key in invalid:
person.api_key = api_key
self.assertRaises(ValidationError, person.validate)
with pytest.raises(ValidationError):
person.validate()

View File

@ -42,11 +42,11 @@ class PickleSignalsTest(Document):
@classmethod
def post_save(self, sender, document, created, **kwargs):
pickled = pickle.dumps(document)
pickle.dumps(document)
@classmethod
def post_delete(self, sender, document, **kwargs):
pickled = pickle.dumps(document)
pickle.dumps(document)
signals.post_save.connect(PickleSignalsTest.post_save, sender=PickleSignalsTest)

View File

@ -1,67 +1,69 @@
import unittest
import pytest
from mongoengine import *
from mongoengine.queryset import QueryFieldList
class TestQueryFieldList(unittest.TestCase):
class TestQueryFieldList:
def test_empty(self):
q = QueryFieldList()
self.assertFalse(q)
assert not q
q = QueryFieldList(always_include=["_cls"])
self.assertFalse(q)
assert not q
def test_include_include(self):
q = QueryFieldList()
q += QueryFieldList(
fields=["a", "b"], value=QueryFieldList.ONLY, _only_called=True
)
self.assertEqual(q.as_dict(), {"a": 1, "b": 1})
assert q.as_dict() == {"a": 1, "b": 1}
q += QueryFieldList(fields=["b", "c"], value=QueryFieldList.ONLY)
self.assertEqual(q.as_dict(), {"a": 1, "b": 1, "c": 1})
assert q.as_dict() == {"a": 1, "b": 1, "c": 1}
def test_include_exclude(self):
q = QueryFieldList()
q += QueryFieldList(fields=["a", "b"], value=QueryFieldList.ONLY)
self.assertEqual(q.as_dict(), {"a": 1, "b": 1})
assert q.as_dict() == {"a": 1, "b": 1}
q += QueryFieldList(fields=["b", "c"], value=QueryFieldList.EXCLUDE)
self.assertEqual(q.as_dict(), {"a": 1})
assert q.as_dict() == {"a": 1}
def test_exclude_exclude(self):
q = QueryFieldList()
q += QueryFieldList(fields=["a", "b"], value=QueryFieldList.EXCLUDE)
self.assertEqual(q.as_dict(), {"a": 0, "b": 0})
assert q.as_dict() == {"a": 0, "b": 0}
q += QueryFieldList(fields=["b", "c"], value=QueryFieldList.EXCLUDE)
self.assertEqual(q.as_dict(), {"a": 0, "b": 0, "c": 0})
assert q.as_dict() == {"a": 0, "b": 0, "c": 0}
def test_exclude_include(self):
q = QueryFieldList()
q += QueryFieldList(fields=["a", "b"], value=QueryFieldList.EXCLUDE)
self.assertEqual(q.as_dict(), {"a": 0, "b": 0})
assert q.as_dict() == {"a": 0, "b": 0}
q += QueryFieldList(fields=["b", "c"], value=QueryFieldList.ONLY)
self.assertEqual(q.as_dict(), {"c": 1})
assert q.as_dict() == {"c": 1}
def test_always_include(self):
q = QueryFieldList(always_include=["x", "y"])
q += QueryFieldList(fields=["a", "b", "x"], value=QueryFieldList.EXCLUDE)
q += QueryFieldList(fields=["b", "c"], value=QueryFieldList.ONLY)
self.assertEqual(q.as_dict(), {"x": 1, "y": 1, "c": 1})
assert q.as_dict() == {"x": 1, "y": 1, "c": 1}
def test_reset(self):
q = QueryFieldList(always_include=["x", "y"])
q += QueryFieldList(fields=["a", "b", "x"], value=QueryFieldList.EXCLUDE)
q += QueryFieldList(fields=["b", "c"], value=QueryFieldList.ONLY)
self.assertEqual(q.as_dict(), {"x": 1, "y": 1, "c": 1})
assert q.as_dict() == {"x": 1, "y": 1, "c": 1}
q.reset()
self.assertFalse(q)
assert not q
q += QueryFieldList(fields=["b", "c"], value=QueryFieldList.ONLY)
self.assertEqual(q.as_dict(), {"x": 1, "y": 1, "b": 1, "c": 1})
assert q.as_dict() == {"x": 1, "y": 1, "b": 1, "c": 1}
def test_using_a_slice(self):
q = QueryFieldList()
q += QueryFieldList(fields=["a"], value={"$slice": 5})
self.assertEqual(q.as_dict(), {"a": {"$slice": 5}})
assert q.as_dict() == {"a": {"$slice": 5}}
class TestOnlyExcludeAll(unittest.TestCase):
@ -90,25 +92,23 @@ class TestOnlyExcludeAll(unittest.TestCase):
only = ["b", "c"]
qs = MyDoc.objects.fields(**{i: 1 for i in include})
self.assertEqual(
qs._loaded_fields.as_dict(), {"a": 1, "b": 1, "c": 1, "d": 1, "e": 1}
)
assert qs._loaded_fields.as_dict() == {"a": 1, "b": 1, "c": 1, "d": 1, "e": 1}
qs = qs.only(*only)
self.assertEqual(qs._loaded_fields.as_dict(), {"b": 1, "c": 1})
assert qs._loaded_fields.as_dict() == {"b": 1, "c": 1}
qs = qs.exclude(*exclude)
self.assertEqual(qs._loaded_fields.as_dict(), {"b": 1, "c": 1})
assert qs._loaded_fields.as_dict() == {"b": 1, "c": 1}
qs = MyDoc.objects.fields(**{i: 1 for i in include})
qs = qs.exclude(*exclude)
self.assertEqual(qs._loaded_fields.as_dict(), {"a": 1, "b": 1, "c": 1})
assert qs._loaded_fields.as_dict() == {"a": 1, "b": 1, "c": 1}
qs = qs.only(*only)
self.assertEqual(qs._loaded_fields.as_dict(), {"b": 1, "c": 1})
assert qs._loaded_fields.as_dict() == {"b": 1, "c": 1}
qs = MyDoc.objects.exclude(*exclude)
qs = qs.fields(**{i: 1 for i in include})
self.assertEqual(qs._loaded_fields.as_dict(), {"a": 1, "b": 1, "c": 1})
assert qs._loaded_fields.as_dict() == {"a": 1, "b": 1, "c": 1}
qs = qs.only(*only)
self.assertEqual(qs._loaded_fields.as_dict(), {"b": 1, "c": 1})
assert qs._loaded_fields.as_dict() == {"b": 1, "c": 1}
def test_slicing(self):
class MyDoc(Document):
@ -127,15 +127,16 @@ class TestOnlyExcludeAll(unittest.TestCase):
qs = qs.exclude(*exclude)
qs = qs.only(*only)
qs = qs.fields(slice__b=5)
self.assertEqual(qs._loaded_fields.as_dict(), {"b": {"$slice": 5}, "c": 1})
assert qs._loaded_fields.as_dict() == {"b": {"$slice": 5}, "c": 1}
qs = qs.fields(slice__c=[5, 1])
self.assertEqual(
qs._loaded_fields.as_dict(), {"b": {"$slice": 5}, "c": {"$slice": [5, 1]}}
)
assert qs._loaded_fields.as_dict() == {
"b": {"$slice": 5},
"c": {"$slice": [5, 1]},
}
qs = qs.exclude("c")
self.assertEqual(qs._loaded_fields.as_dict(), {"b": {"$slice": 5}})
assert qs._loaded_fields.as_dict() == {"b": {"$slice": 5}}
def test_mix_slice_with_other_fields(self):
class MyDoc(Document):
@ -144,7 +145,7 @@ class TestOnlyExcludeAll(unittest.TestCase):
c = ListField()
qs = MyDoc.objects.fields(a=1, b=0, slice__c=2)
self.assertEqual(qs._loaded_fields.as_dict(), {"c": {"$slice": 2}, "a": 1})
assert qs._loaded_fields.as_dict() == {"c": {"$slice": 2}, "a": 1}
def test_only(self):
"""Ensure that QuerySet.only only returns the requested fields.
@ -153,20 +154,20 @@ class TestOnlyExcludeAll(unittest.TestCase):
person.save()
obj = self.Person.objects.only("name").get()
self.assertEqual(obj.name, person.name)
self.assertEqual(obj.age, None)
assert obj.name == person.name
assert obj.age is None
obj = self.Person.objects.only("age").get()
self.assertEqual(obj.name, None)
self.assertEqual(obj.age, person.age)
assert obj.name is None
assert obj.age == person.age
obj = self.Person.objects.only("name", "age").get()
self.assertEqual(obj.name, person.name)
self.assertEqual(obj.age, person.age)
assert obj.name == person.name
assert obj.age == person.age
obj = self.Person.objects.only(*("id", "name")).get()
self.assertEqual(obj.name, person.name)
self.assertEqual(obj.age, None)
assert obj.name == person.name
assert obj.age is None
# Check polymorphism still works
class Employee(self.Person):
@ -176,12 +177,12 @@ class TestOnlyExcludeAll(unittest.TestCase):
employee.save()
obj = self.Person.objects(id=employee.id).only("age").get()
self.assertIsInstance(obj, Employee)
assert isinstance(obj, Employee)
# Check field names are looked up properly
obj = Employee.objects(id=employee.id).only("salary").get()
self.assertEqual(obj.salary, employee.salary)
self.assertEqual(obj.name, None)
assert obj.salary == employee.salary
assert obj.name is None
def test_only_with_subfields(self):
class User(EmbeddedDocument):
@ -215,29 +216,29 @@ class TestOnlyExcludeAll(unittest.TestCase):
post.save()
obj = BlogPost.objects.only("author.name").get()
self.assertEqual(obj.content, None)
self.assertEqual(obj.author.email, None)
self.assertEqual(obj.author.name, "Test User")
self.assertEqual(obj.comments, [])
assert obj.content is None
assert obj.author.email is None
assert obj.author.name == "Test User"
assert obj.comments == []
obj = BlogPost.objects.only("various.test_dynamic.some").get()
self.assertEqual(obj.various["test_dynamic"].some, True)
assert obj.various["test_dynamic"].some is True
obj = BlogPost.objects.only("content", "comments.title").get()
self.assertEqual(obj.content, "Had a good coffee today...")
self.assertEqual(obj.author, None)
self.assertEqual(obj.comments[0].title, "I aggree")
self.assertEqual(obj.comments[1].title, "Coffee")
self.assertEqual(obj.comments[0].text, None)
self.assertEqual(obj.comments[1].text, None)
assert obj.content == "Had a good coffee today..."
assert obj.author is None
assert obj.comments[0].title == "I aggree"
assert obj.comments[1].title == "Coffee"
assert obj.comments[0].text is None
assert obj.comments[1].text is None
obj = BlogPost.objects.only("comments").get()
self.assertEqual(obj.content, None)
self.assertEqual(obj.author, None)
self.assertEqual(obj.comments[0].title, "I aggree")
self.assertEqual(obj.comments[1].title, "Coffee")
self.assertEqual(obj.comments[0].text, "Great post!")
self.assertEqual(obj.comments[1].text, "I hate coffee")
assert obj.content is None
assert obj.author is None
assert obj.comments[0].title == "I aggree"
assert obj.comments[1].title == "Coffee"
assert obj.comments[0].text == "Great post!"
assert obj.comments[1].text == "I hate coffee"
BlogPost.drop_collection()
@ -266,10 +267,10 @@ class TestOnlyExcludeAll(unittest.TestCase):
post.save()
obj = BlogPost.objects.exclude("author", "comments.text").get()
self.assertEqual(obj.author, None)
self.assertEqual(obj.content, "Had a good coffee today...")
self.assertEqual(obj.comments[0].title, "I aggree")
self.assertEqual(obj.comments[0].text, None)
assert obj.author is None
assert obj.content == "Had a good coffee today..."
assert obj.comments[0].title == "I aggree"
assert obj.comments[0].text is None
BlogPost.drop_collection()
@ -301,18 +302,18 @@ class TestOnlyExcludeAll(unittest.TestCase):
email.save()
obj = Email.objects.exclude("content_type").exclude("body").get()
self.assertEqual(obj.sender, "me")
self.assertEqual(obj.to, "you")
self.assertEqual(obj.subject, "From Russia with Love")
self.assertEqual(obj.body, None)
self.assertEqual(obj.content_type, None)
assert obj.sender == "me"
assert obj.to == "you"
assert obj.subject == "From Russia with Love"
assert obj.body is None
assert obj.content_type is None
obj = Email.objects.only("sender", "to").exclude("body", "sender").get()
self.assertEqual(obj.sender, None)
self.assertEqual(obj.to, "you")
self.assertEqual(obj.subject, None)
self.assertEqual(obj.body, None)
self.assertEqual(obj.content_type, None)
assert obj.sender is None
assert obj.to == "you"
assert obj.subject is None
assert obj.body is None
assert obj.content_type is None
obj = (
Email.objects.exclude("attachments.content")
@ -320,13 +321,13 @@ class TestOnlyExcludeAll(unittest.TestCase):
.only("to", "attachments.name")
.get()
)
self.assertEqual(obj.attachments[0].name, "file1.doc")
self.assertEqual(obj.attachments[0].content, None)
self.assertEqual(obj.sender, None)
self.assertEqual(obj.to, "you")
self.assertEqual(obj.subject, None)
self.assertEqual(obj.body, None)
self.assertEqual(obj.content_type, None)
assert obj.attachments[0].name == "file1.doc"
assert obj.attachments[0].content is None
assert obj.sender is None
assert obj.to == "you"
assert obj.subject is None
assert obj.body is None
assert obj.content_type is None
Email.drop_collection()
@ -355,11 +356,11 @@ class TestOnlyExcludeAll(unittest.TestCase):
.all_fields()
.get()
)
self.assertEqual(obj.sender, "me")
self.assertEqual(obj.to, "you")
self.assertEqual(obj.subject, "From Russia with Love")
self.assertEqual(obj.body, "Hello!")
self.assertEqual(obj.content_type, "text/plain")
assert obj.sender == "me"
assert obj.to == "you"
assert obj.subject == "From Russia with Love"
assert obj.body == "Hello!"
assert obj.content_type == "text/plain"
Email.drop_collection()
@ -377,27 +378,27 @@ class TestOnlyExcludeAll(unittest.TestCase):
# first three
numbers = Numbers.objects.fields(slice__n=3).get()
self.assertEqual(numbers.n, [0, 1, 2])
assert numbers.n == [0, 1, 2]
# last three
numbers = Numbers.objects.fields(slice__n=-3).get()
self.assertEqual(numbers.n, [-3, -2, -1])
assert numbers.n == [-3, -2, -1]
# skip 2, limit 3
numbers = Numbers.objects.fields(slice__n=[2, 3]).get()
self.assertEqual(numbers.n, [2, 3, 4])
assert numbers.n == [2, 3, 4]
# skip to fifth from last, limit 4
numbers = Numbers.objects.fields(slice__n=[-5, 4]).get()
self.assertEqual(numbers.n, [-5, -4, -3, -2])
assert numbers.n == [-5, -4, -3, -2]
# skip to fifth from last, limit 10
numbers = Numbers.objects.fields(slice__n=[-5, 10]).get()
self.assertEqual(numbers.n, [-5, -4, -3, -2, -1])
assert numbers.n == [-5, -4, -3, -2, -1]
# skip to fifth from last, limit 10 dict method
numbers = Numbers.objects.fields(n={"$slice": [-5, 10]}).get()
self.assertEqual(numbers.n, [-5, -4, -3, -2, -1])
assert numbers.n == [-5, -4, -3, -2, -1]
def test_slicing_nested_fields(self):
"""Ensure that query slicing an embedded array works.
@ -417,27 +418,27 @@ class TestOnlyExcludeAll(unittest.TestCase):
# first three
numbers = Numbers.objects.fields(slice__embedded__n=3).get()
self.assertEqual(numbers.embedded.n, [0, 1, 2])
assert numbers.embedded.n == [0, 1, 2]
# last three
numbers = Numbers.objects.fields(slice__embedded__n=-3).get()
self.assertEqual(numbers.embedded.n, [-3, -2, -1])
assert numbers.embedded.n == [-3, -2, -1]
# skip 2, limit 3
numbers = Numbers.objects.fields(slice__embedded__n=[2, 3]).get()
self.assertEqual(numbers.embedded.n, [2, 3, 4])
assert numbers.embedded.n == [2, 3, 4]
# skip to fifth from last, limit 4
numbers = Numbers.objects.fields(slice__embedded__n=[-5, 4]).get()
self.assertEqual(numbers.embedded.n, [-5, -4, -3, -2])
assert numbers.embedded.n == [-5, -4, -3, -2]
# skip to fifth from last, limit 10
numbers = Numbers.objects.fields(slice__embedded__n=[-5, 10]).get()
self.assertEqual(numbers.embedded.n, [-5, -4, -3, -2, -1])
assert numbers.embedded.n == [-5, -4, -3, -2, -1]
# skip to fifth from last, limit 10 dict method
numbers = Numbers.objects.fields(embedded__n={"$slice": [-5, 10]}).get()
self.assertEqual(numbers.embedded.n, [-5, -4, -3, -2, -1])
assert numbers.embedded.n == [-5, -4, -3, -2, -1]
def test_exclude_from_subclasses_docs(self):
class Base(Document):
@ -456,9 +457,10 @@ class TestOnlyExcludeAll(unittest.TestCase):
User(username="mongodb", password="secret").save()
user = Base.objects().exclude("password", "wibble").first()
self.assertEqual(user.password, None)
assert user.password is None
self.assertRaises(LookUpError, Base.objects.exclude, "made_up")
with pytest.raises(LookUpError):
Base.objects.exclude("made_up")
if __name__ == "__main__":

View File

@ -48,14 +48,14 @@ class TestGeoQueries(MongoDBTestCase):
# note that "near" will show the san francisco event, too,
# although it sorts to last.
events = self.Event.objects(location__near=[-87.67892, 41.9120459])
self.assertEqual(events.count(), 3)
self.assertEqual(list(events), [event1, event3, event2])
assert events.count() == 3
assert list(events) == [event1, event3, event2]
# ensure ordering is respected by "near"
events = self.Event.objects(location__near=[-87.67892, 41.9120459])
events = events.order_by("-date")
self.assertEqual(events.count(), 3)
self.assertEqual(list(events), [event3, event1, event2])
assert events.count() == 3
assert list(events) == [event3, event1, event2]
def test_near_and_max_distance(self):
"""Ensure the "max_distance" operator works alongside the "near"
@ -66,8 +66,8 @@ class TestGeoQueries(MongoDBTestCase):
# find events within 10 degrees of san francisco
point = [-122.415579, 37.7566023]
events = self.Event.objects(location__near=point, location__max_distance=10)
self.assertEqual(events.count(), 1)
self.assertEqual(events[0], event2)
assert events.count() == 1
assert events[0] == event2
def test_near_and_min_distance(self):
"""Ensure the "min_distance" operator works alongside the "near"
@ -78,7 +78,7 @@ class TestGeoQueries(MongoDBTestCase):
# find events at least 10 degrees away of san francisco
point = [-122.415579, 37.7566023]
events = self.Event.objects(location__near=point, location__min_distance=10)
self.assertEqual(events.count(), 2)
assert events.count() == 2
def test_within_distance(self):
"""Make sure the "within_distance" operator works."""
@ -87,29 +87,29 @@ class TestGeoQueries(MongoDBTestCase):
# find events within 5 degrees of pitchfork office, chicago
point_and_distance = [[-87.67892, 41.9120459], 5]
events = self.Event.objects(location__within_distance=point_and_distance)
self.assertEqual(events.count(), 2)
assert events.count() == 2
events = list(events)
self.assertNotIn(event2, events)
self.assertIn(event1, events)
self.assertIn(event3, events)
assert event2 not in events
assert event1 in events
assert event3 in events
# find events within 10 degrees of san francisco
point_and_distance = [[-122.415579, 37.7566023], 10]
events = self.Event.objects(location__within_distance=point_and_distance)
self.assertEqual(events.count(), 1)
self.assertEqual(events[0], event2)
assert events.count() == 1
assert events[0] == event2
# find events within 1 degree of greenpoint, broolyn, nyc, ny
point_and_distance = [[-73.9509714, 40.7237134], 1]
events = self.Event.objects(location__within_distance=point_and_distance)
self.assertEqual(events.count(), 0)
assert events.count() == 0
# ensure ordering is respected by "within_distance"
point_and_distance = [[-87.67892, 41.9120459], 10]
events = self.Event.objects(location__within_distance=point_and_distance)
events = events.order_by("-date")
self.assertEqual(events.count(), 2)
self.assertEqual(events[0], event3)
assert events.count() == 2
assert events[0] == event3
def test_within_box(self):
"""Ensure the "within_box" operator works."""
@ -118,8 +118,8 @@ class TestGeoQueries(MongoDBTestCase):
# check that within_box works
box = [(-125.0, 35.0), (-100.0, 40.0)]
events = self.Event.objects(location__within_box=box)
self.assertEqual(events.count(), 1)
self.assertEqual(events[0].id, event2.id)
assert events.count() == 1
assert events[0].id == event2.id
def test_within_polygon(self):
"""Ensure the "within_polygon" operator works."""
@ -133,8 +133,8 @@ class TestGeoQueries(MongoDBTestCase):
(-87.656164, 41.898061),
]
events = self.Event.objects(location__within_polygon=polygon)
self.assertEqual(events.count(), 1)
self.assertEqual(events[0].id, event1.id)
assert events.count() == 1
assert events[0].id == event1.id
polygon2 = [
(-1.742249, 54.033586),
@ -142,7 +142,7 @@ class TestGeoQueries(MongoDBTestCase):
(-4.40094, 53.389881),
]
events = self.Event.objects(location__within_polygon=polygon2)
self.assertEqual(events.count(), 0)
assert events.count() == 0
def test_2dsphere_near(self):
"""Make sure the "near" operator works with a PointField, which
@ -154,14 +154,14 @@ class TestGeoQueries(MongoDBTestCase):
# note that "near" will show the san francisco event, too,
# although it sorts to last.
events = self.Event.objects(location__near=[-87.67892, 41.9120459])
self.assertEqual(events.count(), 3)
self.assertEqual(list(events), [event1, event3, event2])
assert events.count() == 3
assert list(events) == [event1, event3, event2]
# ensure ordering is respected by "near"
events = self.Event.objects(location__near=[-87.67892, 41.9120459])
events = events.order_by("-date")
self.assertEqual(events.count(), 3)
self.assertEqual(list(events), [event3, event1, event2])
assert events.count() == 3
assert list(events) == [event3, event1, event2]
def test_2dsphere_near_and_max_distance(self):
"""Ensure the "max_distance" operator works alongside the "near"
@ -172,21 +172,21 @@ class TestGeoQueries(MongoDBTestCase):
# find events within 10km of san francisco
point = [-122.415579, 37.7566023]
events = self.Event.objects(location__near=point, location__max_distance=10000)
self.assertEqual(events.count(), 1)
self.assertEqual(events[0], event2)
assert events.count() == 1
assert events[0] == event2
# find events within 1km of greenpoint, broolyn, nyc, ny
events = self.Event.objects(
location__near=[-73.9509714, 40.7237134], location__max_distance=1000
)
self.assertEqual(events.count(), 0)
assert events.count() == 0
# ensure ordering is respected by "near"
events = self.Event.objects(
location__near=[-87.67892, 41.9120459], location__max_distance=10000
).order_by("-date")
self.assertEqual(events.count(), 2)
self.assertEqual(events[0], event3)
assert events.count() == 2
assert events[0] == event3
def test_2dsphere_geo_within_box(self):
"""Ensure the "geo_within_box" operator works with a 2dsphere
@ -197,8 +197,8 @@ class TestGeoQueries(MongoDBTestCase):
# check that within_box works
box = [(-125.0, 35.0), (-100.0, 40.0)]
events = self.Event.objects(location__geo_within_box=box)
self.assertEqual(events.count(), 1)
self.assertEqual(events[0].id, event2.id)
assert events.count() == 1
assert events[0].id == event2.id
def test_2dsphere_geo_within_polygon(self):
"""Ensure the "geo_within_polygon" operator works with a
@ -214,8 +214,8 @@ class TestGeoQueries(MongoDBTestCase):
(-87.656164, 41.898061),
]
events = self.Event.objects(location__geo_within_polygon=polygon)
self.assertEqual(events.count(), 1)
self.assertEqual(events[0].id, event1.id)
assert events.count() == 1
assert events[0].id == event1.id
polygon2 = [
(-1.742249, 54.033586),
@ -223,7 +223,7 @@ class TestGeoQueries(MongoDBTestCase):
(-4.40094, 53.389881),
]
events = self.Event.objects(location__geo_within_polygon=polygon2)
self.assertEqual(events.count(), 0)
assert events.count() == 0
def test_2dsphere_near_and_min_max_distance(self):
"""Ensure "min_distace" and "max_distance" operators work well
@ -237,15 +237,15 @@ class TestGeoQueries(MongoDBTestCase):
location__min_distance=1000,
location__max_distance=10000,
).order_by("-date")
self.assertEqual(events.count(), 1)
self.assertEqual(events[0], event3)
assert events.count() == 1
assert events[0] == event3
# ensure ordering is respected by "near" with "min_distance"
events = self.Event.objects(
location__near=[-87.67892, 41.9120459], location__min_distance=10000
).order_by("-date")
self.assertEqual(events.count(), 1)
self.assertEqual(events[0], event2)
assert events.count() == 1
assert events[0] == event2
def test_2dsphere_geo_within_center(self):
"""Make sure the "geo_within_center" operator works with a
@ -256,11 +256,11 @@ class TestGeoQueries(MongoDBTestCase):
# find events within 5 degrees of pitchfork office, chicago
point_and_distance = [[-87.67892, 41.9120459], 2]
events = self.Event.objects(location__geo_within_center=point_and_distance)
self.assertEqual(events.count(), 2)
assert events.count() == 2
events = list(events)
self.assertNotIn(event2, events)
self.assertIn(event1, events)
self.assertIn(event3, events)
assert event2 not in events
assert event1 in events
assert event3 in events
def _test_embedded(self, point_field_class):
"""Helper test method ensuring given point field class works
@ -290,8 +290,8 @@ class TestGeoQueries(MongoDBTestCase):
# note that "near" will show the san francisco event, too,
# although it sorts to last.
events = Event.objects(venue__location__near=[-87.67892, 41.9120459])
self.assertEqual(events.count(), 3)
self.assertEqual(list(events), [event1, event3, event2])
assert events.count() == 3
assert list(events) == [event1, event3, event2]
def test_geo_spatial_embedded(self):
"""Make sure GeoPointField works properly in an embedded document."""
@ -319,55 +319,55 @@ class TestGeoQueries(MongoDBTestCase):
# Finds both points because they are within 60 km of the reference
# point equidistant between them.
points = Point.objects(location__near_sphere=[-122, 37.5])
self.assertEqual(points.count(), 2)
assert points.count() == 2
# Same behavior for _within_spherical_distance
points = Point.objects(
location__within_spherical_distance=[[-122, 37.5], 60 / earth_radius]
)
self.assertEqual(points.count(), 2)
assert points.count() == 2
points = Point.objects(
location__near_sphere=[-122, 37.5], location__max_distance=60 / earth_radius
)
self.assertEqual(points.count(), 2)
assert points.count() == 2
# Test query works with max_distance, being farer from one point
points = Point.objects(
location__near_sphere=[-122, 37.8], location__max_distance=60 / earth_radius
)
close_point = points.first()
self.assertEqual(points.count(), 1)
assert points.count() == 1
# Test query works with min_distance, being farer from one point
points = Point.objects(
location__near_sphere=[-122, 37.8], location__min_distance=60 / earth_radius
)
self.assertEqual(points.count(), 1)
assert points.count() == 1
far_point = points.first()
self.assertNotEqual(close_point, far_point)
assert close_point != far_point
# Finds both points, but orders the north point first because it's
# closer to the reference point to the north.
points = Point.objects(location__near_sphere=[-122, 38.5])
self.assertEqual(points.count(), 2)
self.assertEqual(points[0].id, north_point.id)
self.assertEqual(points[1].id, south_point.id)
assert points.count() == 2
assert points[0].id == north_point.id
assert points[1].id == south_point.id
# Finds both points, but orders the south point first because it's
# closer to the reference point to the south.
points = Point.objects(location__near_sphere=[-122, 36.5])
self.assertEqual(points.count(), 2)
self.assertEqual(points[0].id, south_point.id)
self.assertEqual(points[1].id, north_point.id)
assert points.count() == 2
assert points[0].id == south_point.id
assert points[1].id == north_point.id
# Finds only one point because only the first point is within 60km of
# the reference point to the south.
points = Point.objects(
location__within_spherical_distance=[[-122, 36.5], 60 / earth_radius]
)
self.assertEqual(points.count(), 1)
self.assertEqual(points[0].id, south_point.id)
assert points.count() == 1
assert points[0].id == south_point.id
def test_linestring(self):
class Road(Document):
@ -381,13 +381,13 @@ class TestGeoQueries(MongoDBTestCase):
# near
point = {"type": "Point", "coordinates": [40, 5]}
roads = Road.objects.filter(line__near=point["coordinates"]).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(line__near=point).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(line__near={"$geometry": point}).count()
self.assertEqual(1, roads)
assert 1 == roads
# Within
polygon = {
@ -395,37 +395,37 @@ class TestGeoQueries(MongoDBTestCase):
"coordinates": [[[40, 5], [40, 6], [41, 6], [41, 5], [40, 5]]],
}
roads = Road.objects.filter(line__geo_within=polygon["coordinates"]).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(line__geo_within=polygon).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(line__geo_within={"$geometry": polygon}).count()
self.assertEqual(1, roads)
assert 1 == roads
# Intersects
line = {"type": "LineString", "coordinates": [[40, 5], [40, 6]]}
roads = Road.objects.filter(line__geo_intersects=line["coordinates"]).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(line__geo_intersects=line).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(line__geo_intersects={"$geometry": line}).count()
self.assertEqual(1, roads)
assert 1 == roads
polygon = {
"type": "Polygon",
"coordinates": [[[40, 5], [40, 6], [41, 6], [41, 5], [40, 5]]],
}
roads = Road.objects.filter(line__geo_intersects=polygon["coordinates"]).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(line__geo_intersects=polygon).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(line__geo_intersects={"$geometry": polygon}).count()
self.assertEqual(1, roads)
assert 1 == roads
def test_polygon(self):
class Road(Document):
@ -439,13 +439,13 @@ class TestGeoQueries(MongoDBTestCase):
# near
point = {"type": "Point", "coordinates": [40, 5]}
roads = Road.objects.filter(poly__near=point["coordinates"]).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(poly__near=point).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(poly__near={"$geometry": point}).count()
self.assertEqual(1, roads)
assert 1 == roads
# Within
polygon = {
@ -453,37 +453,37 @@ class TestGeoQueries(MongoDBTestCase):
"coordinates": [[[40, 5], [40, 6], [41, 6], [41, 5], [40, 5]]],
}
roads = Road.objects.filter(poly__geo_within=polygon["coordinates"]).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(poly__geo_within=polygon).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(poly__geo_within={"$geometry": polygon}).count()
self.assertEqual(1, roads)
assert 1 == roads
# Intersects
line = {"type": "LineString", "coordinates": [[40, 5], [41, 6]]}
roads = Road.objects.filter(poly__geo_intersects=line["coordinates"]).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(poly__geo_intersects=line).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(poly__geo_intersects={"$geometry": line}).count()
self.assertEqual(1, roads)
assert 1 == roads
polygon = {
"type": "Polygon",
"coordinates": [[[40, 5], [40, 6], [41, 6], [41, 5], [40, 5]]],
}
roads = Road.objects.filter(poly__geo_intersects=polygon["coordinates"]).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(poly__geo_intersects=polygon).count()
self.assertEqual(1, roads)
assert 1 == roads
roads = Road.objects.filter(poly__geo_intersects={"$geometry": polygon}).count()
self.assertEqual(1, roads)
assert 1 == roads
def test_aspymongo_with_only(self):
"""Ensure as_pymongo works with only"""
@ -495,13 +495,10 @@ class TestGeoQueries(MongoDBTestCase):
p = Place(location=[24.946861267089844, 60.16311983618494])
p.save()
qs = Place.objects().only("location")
self.assertDictEqual(
qs.as_pymongo()[0]["location"],
{
u"type": u"Point",
u"coordinates": [24.946861267089844, 60.16311983618494],
},
)
assert qs.as_pymongo()[0]["location"] == {
u"type": u"Point",
u"coordinates": [24.946861267089844, 60.16311983618494],
}
def test_2dsphere_point_sets_correctly(self):
class Location(Document):
@ -511,11 +508,11 @@ class TestGeoQueries(MongoDBTestCase):
Location(loc=[1, 2]).save()
loc = Location.objects.as_pymongo()[0]
self.assertEqual(loc["loc"], {"type": "Point", "coordinates": [1, 2]})
assert loc["loc"] == {"type": "Point", "coordinates": [1, 2]}
Location.objects.update(set__loc=[2, 1])
loc = Location.objects.as_pymongo()[0]
self.assertEqual(loc["loc"], {"type": "Point", "coordinates": [2, 1]})
assert loc["loc"] == {"type": "Point", "coordinates": [2, 1]}
def test_2dsphere_linestring_sets_correctly(self):
class Location(Document):
@ -525,15 +522,11 @@ class TestGeoQueries(MongoDBTestCase):
Location(line=[[1, 2], [2, 2]]).save()
loc = Location.objects.as_pymongo()[0]
self.assertEqual(
loc["line"], {"type": "LineString", "coordinates": [[1, 2], [2, 2]]}
)
assert loc["line"] == {"type": "LineString", "coordinates": [[1, 2], [2, 2]]}
Location.objects.update(set__line=[[2, 1], [1, 2]])
loc = Location.objects.as_pymongo()[0]
self.assertEqual(
loc["line"], {"type": "LineString", "coordinates": [[2, 1], [1, 2]]}
)
assert loc["line"] == {"type": "LineString", "coordinates": [[2, 1], [1, 2]]}
def test_geojson_PolygonField(self):
class Location(Document):
@ -543,17 +536,17 @@ class TestGeoQueries(MongoDBTestCase):
Location(poly=[[[40, 5], [40, 6], [41, 6], [40, 5]]]).save()
loc = Location.objects.as_pymongo()[0]
self.assertEqual(
loc["poly"],
{"type": "Polygon", "coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]]},
)
assert loc["poly"] == {
"type": "Polygon",
"coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]],
}
Location.objects.update(set__poly=[[[40, 4], [40, 6], [41, 6], [40, 4]]])
loc = Location.objects.as_pymongo()[0]
self.assertEqual(
loc["poly"],
{"type": "Polygon", "coordinates": [[[40, 4], [40, 6], [41, 6], [40, 4]]]},
)
assert loc["poly"] == {
"type": "Polygon",
"coordinates": [[[40, 4], [40, 6], [41, 6], [40, 4]]],
}
if __name__ == "__main__":

View File

@ -14,14 +14,14 @@ class TestFindAndModify(unittest.TestCase):
Doc.drop_collection()
def assertDbEqual(self, docs):
self.assertEqual(list(Doc._collection.find().sort("id")), docs)
assert list(Doc._collection.find().sort("id")) == docs
def test_modify(self):
Doc(id=0, value=0).save()
doc = Doc(id=1, value=1).save()
old_doc = Doc.objects(id=1).modify(set__value=-1)
self.assertEqual(old_doc.to_json(), doc.to_json())
assert old_doc.to_json() == doc.to_json()
self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": -1}])
def test_modify_with_new(self):
@ -30,18 +30,18 @@ class TestFindAndModify(unittest.TestCase):
new_doc = Doc.objects(id=1).modify(set__value=-1, new=True)
doc.value = -1
self.assertEqual(new_doc.to_json(), doc.to_json())
assert new_doc.to_json() == doc.to_json()
self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": -1}])
def test_modify_not_existing(self):
Doc(id=0, value=0).save()
self.assertEqual(Doc.objects(id=1).modify(set__value=-1), None)
assert Doc.objects(id=1).modify(set__value=-1) is None
self.assertDbEqual([{"_id": 0, "value": 0}])
def test_modify_with_upsert(self):
Doc(id=0, value=0).save()
old_doc = Doc.objects(id=1).modify(set__value=1, upsert=True)
self.assertEqual(old_doc, None)
assert old_doc is None
self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": 1}])
def test_modify_with_upsert_existing(self):
@ -49,13 +49,13 @@ class TestFindAndModify(unittest.TestCase):
doc = Doc(id=1, value=1).save()
old_doc = Doc.objects(id=1).modify(set__value=-1, upsert=True)
self.assertEqual(old_doc.to_json(), doc.to_json())
assert old_doc.to_json() == doc.to_json()
self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": -1}])
def test_modify_with_upsert_with_new(self):
Doc(id=0, value=0).save()
new_doc = Doc.objects(id=1).modify(upsert=True, new=True, set__value=1)
self.assertEqual(new_doc.to_mongo(), {"_id": 1, "value": 1})
assert new_doc.to_mongo() == {"_id": 1, "value": 1}
self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": 1}])
def test_modify_with_remove(self):
@ -63,12 +63,12 @@ class TestFindAndModify(unittest.TestCase):
doc = Doc(id=1, value=1).save()
old_doc = Doc.objects(id=1).modify(remove=True)
self.assertEqual(old_doc.to_json(), doc.to_json())
assert old_doc.to_json() == doc.to_json()
self.assertDbEqual([{"_id": 0, "value": 0}])
def test_find_and_modify_with_remove_not_existing(self):
Doc(id=0, value=0).save()
self.assertEqual(Doc.objects(id=1).modify(remove=True), None)
assert Doc.objects(id=1).modify(remove=True) is None
self.assertDbEqual([{"_id": 0, "value": 0}])
def test_modify_with_order_by(self):
@ -78,7 +78,7 @@ class TestFindAndModify(unittest.TestCase):
doc = Doc(id=3, value=0).save()
old_doc = Doc.objects().order_by("-id").modify(set__value=-1)
self.assertEqual(old_doc.to_json(), doc.to_json())
assert old_doc.to_json() == doc.to_json()
self.assertDbEqual(
[
{"_id": 0, "value": 3},
@ -93,7 +93,7 @@ class TestFindAndModify(unittest.TestCase):
Doc(id=1, value=1).save()
old_doc = Doc.objects(id=1).only("id").modify(set__value=-1)
self.assertEqual(old_doc.to_mongo(), {"_id": 1})
assert old_doc.to_mongo() == {"_id": 1}
self.assertDbEqual([{"_id": 0, "value": 0}, {"_id": 1, "value": -1}])
def test_modify_with_push(self):
@ -106,23 +106,23 @@ class TestFindAndModify(unittest.TestCase):
# Push a new tag via modify with new=False (default).
BlogPost(id=blog.id).modify(push__tags="code")
self.assertEqual(blog.tags, [])
assert blog.tags == []
blog.reload()
self.assertEqual(blog.tags, ["code"])
assert blog.tags == ["code"]
# Push a new tag via modify with new=True.
blog = BlogPost.objects(id=blog.id).modify(push__tags="java", new=True)
self.assertEqual(blog.tags, ["code", "java"])
assert blog.tags == ["code", "java"]
# Push a new tag with a positional argument.
blog = BlogPost.objects(id=blog.id).modify(push__tags__0="python", new=True)
self.assertEqual(blog.tags, ["python", "code", "java"])
assert blog.tags == ["python", "code", "java"]
# Push multiple new tags with a positional argument.
blog = BlogPost.objects(id=blog.id).modify(
push__tags__1=["go", "rust"], new=True
)
self.assertEqual(blog.tags, ["python", "go", "rust", "code", "java"])
assert blog.tags == ["python", "go", "rust", "code", "java"]
if __name__ == "__main__":

View File

@ -37,13 +37,13 @@ class TestQuerysetPickable(MongoDBTestCase):
loadedQs = self._get_loaded(qs)
self.assertEqual(qs.count(), loadedQs.count())
assert qs.count() == loadedQs.count()
# can update loadedQs
loadedQs.update(age=23)
# check
self.assertEqual(Person.objects.first().age, 23)
assert Person.objects.first().age == 23
def test_pickle_support_filtration(self):
Person.objects.create(name="Alice", age=22)
@ -51,9 +51,9 @@ class TestQuerysetPickable(MongoDBTestCase):
Person.objects.create(name="Bob", age=23)
qs = Person.objects.filter(age__gte=22)
self.assertEqual(qs.count(), 2)
assert qs.count() == 2
loaded = self._get_loaded(qs)
self.assertEqual(loaded.count(), 2)
self.assertEqual(loaded.filter(name="Bob").first().age, 23)
assert loaded.count() == 2
assert loaded.filter(name="Bob").first().age == 23

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,255 @@
# -*- coding: utf-8 -*-
import unittest
import warnings
from pymongo.read_preferences import ReadPreference
from mongoengine import *
from tests.utils import MongoDBTestCase
class TestQuerysetAggregate(MongoDBTestCase):
def test_read_preference_aggregation_framework(self):
class Bar(Document):
txt = StringField()
meta = {"indexes": ["txt"]}
# Aggregates with read_preference
pipeline = []
bars = Bar.objects.read_preference(
ReadPreference.SECONDARY_PREFERRED
).aggregate(pipeline)
assert (
bars._CommandCursor__collection.read_preference
== ReadPreference.SECONDARY_PREFERRED
)
def test_queryset_aggregation_framework(self):
class Person(Document):
name = StringField()
age = IntField()
Person.drop_collection()
p1 = Person(name="Isabella Luanna", age=16)
p2 = Person(name="Wilson Junior", age=21)
p3 = Person(name="Sandra Mara", age=37)
Person.objects.insert([p1, p2, p3])
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
data = Person.objects(age__lte=22).aggregate(pipeline)
assert list(data) == [
{"_id": p1.pk, "name": "ISABELLA LUANNA"},
{"_id": p2.pk, "name": "WILSON JUNIOR"},
]
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
data = Person.objects(age__lte=22).order_by("-name").aggregate(pipeline)
assert list(data) == [
{"_id": p2.pk, "name": "WILSON JUNIOR"},
{"_id": p1.pk, "name": "ISABELLA LUANNA"},
]
pipeline = [
{"$group": {"_id": None, "total": {"$sum": 1}, "avg": {"$avg": "$age"}}}
]
data = (
Person.objects(age__gte=17, age__lte=40)
.order_by("-age")
.aggregate(pipeline)
)
assert list(data) == [{"_id": None, "avg": 29, "total": 2}]
pipeline = [{"$match": {"name": "Isabella Luanna"}}]
data = Person.objects().aggregate(pipeline)
assert list(data) == [{u"_id": p1.pk, u"age": 16, u"name": u"Isabella Luanna"}]
def test_queryset_aggregation_with_skip(self):
class Person(Document):
name = StringField()
age = IntField()
Person.drop_collection()
p1 = Person(name="Isabella Luanna", age=16)
p2 = Person(name="Wilson Junior", age=21)
p3 = Person(name="Sandra Mara", age=37)
Person.objects.insert([p1, p2, p3])
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
data = Person.objects.skip(1).aggregate(pipeline)
assert list(data) == [
{"_id": p2.pk, "name": "WILSON JUNIOR"},
{"_id": p3.pk, "name": "SANDRA MARA"},
]
def test_queryset_aggregation_with_limit(self):
class Person(Document):
name = StringField()
age = IntField()
Person.drop_collection()
p1 = Person(name="Isabella Luanna", age=16)
p2 = Person(name="Wilson Junior", age=21)
p3 = Person(name="Sandra Mara", age=37)
Person.objects.insert([p1, p2, p3])
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
data = Person.objects.limit(1).aggregate(pipeline)
assert list(data) == [{"_id": p1.pk, "name": "ISABELLA LUANNA"}]
def test_queryset_aggregation_with_sort(self):
class Person(Document):
name = StringField()
age = IntField()
Person.drop_collection()
p1 = Person(name="Isabella Luanna", age=16)
p2 = Person(name="Wilson Junior", age=21)
p3 = Person(name="Sandra Mara", age=37)
Person.objects.insert([p1, p2, p3])
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
data = Person.objects.order_by("name").aggregate(pipeline)
assert list(data) == [
{"_id": p1.pk, "name": "ISABELLA LUANNA"},
{"_id": p3.pk, "name": "SANDRA MARA"},
{"_id": p2.pk, "name": "WILSON JUNIOR"},
]
def test_queryset_aggregation_with_skip_with_limit(self):
class Person(Document):
name = StringField()
age = IntField()
Person.drop_collection()
p1 = Person(name="Isabella Luanna", age=16)
p2 = Person(name="Wilson Junior", age=21)
p3 = Person(name="Sandra Mara", age=37)
Person.objects.insert([p1, p2, p3])
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
data = list(Person.objects.skip(1).limit(1).aggregate(pipeline))
assert list(data) == [{"_id": p2.pk, "name": "WILSON JUNIOR"}]
# Make sure limit/skip chaining order has no impact
data2 = Person.objects.limit(1).skip(1).aggregate(pipeline)
assert data == list(data2)
def test_queryset_aggregation_with_sort_with_limit(self):
class Person(Document):
name = StringField()
age = IntField()
Person.drop_collection()
p1 = Person(name="Isabella Luanna", age=16)
p2 = Person(name="Wilson Junior", age=21)
p3 = Person(name="Sandra Mara", age=37)
Person.objects.insert([p1, p2, p3])
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
data = Person.objects.order_by("name").limit(2).aggregate(pipeline)
assert list(data) == [
{"_id": p1.pk, "name": "ISABELLA LUANNA"},
{"_id": p3.pk, "name": "SANDRA MARA"},
]
# Verify adding limit/skip steps works as expected
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}, {"$limit": 1}]
data = Person.objects.order_by("name").limit(2).aggregate(pipeline)
assert list(data) == [{"_id": p1.pk, "name": "ISABELLA LUANNA"}]
pipeline = [
{"$project": {"name": {"$toUpper": "$name"}}},
{"$skip": 1},
{"$limit": 1},
]
data = Person.objects.order_by("name").limit(2).aggregate(pipeline)
assert list(data) == [{"_id": p3.pk, "name": "SANDRA MARA"}]
def test_queryset_aggregation_with_sort_with_skip(self):
class Person(Document):
name = StringField()
age = IntField()
Person.drop_collection()
p1 = Person(name="Isabella Luanna", age=16)
p2 = Person(name="Wilson Junior", age=21)
p3 = Person(name="Sandra Mara", age=37)
Person.objects.insert([p1, p2, p3])
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
data = Person.objects.order_by("name").skip(2).aggregate(pipeline)
assert list(data) == [{"_id": p2.pk, "name": "WILSON JUNIOR"}]
def test_queryset_aggregation_with_sort_with_skip_with_limit(self):
class Person(Document):
name = StringField()
age = IntField()
Person.drop_collection()
p1 = Person(name="Isabella Luanna", age=16)
p2 = Person(name="Wilson Junior", age=21)
p3 = Person(name="Sandra Mara", age=37)
Person.objects.insert([p1, p2, p3])
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
data = Person.objects.order_by("name").skip(1).limit(1).aggregate(pipeline)
assert list(data) == [{"_id": p3.pk, "name": "SANDRA MARA"}]
def test_queryset_aggregation_deprecated_interface(self):
class Person(Document):
name = StringField()
Person.drop_collection()
p1 = Person(name="Isabella Luanna")
p2 = Person(name="Wilson Junior")
p3 = Person(name="Sandra Mara")
Person.objects.insert([p1, p2, p3])
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}]
# Make sure a warning is emitted
with warnings.catch_warnings():
warnings.simplefilter("error", DeprecationWarning)
with self.assertRaises(DeprecationWarning):
Person.objects.order_by("name").limit(2).aggregate(*pipeline)
# Make sure old interface works as expected with a 1-step pipeline
data = Person.objects.order_by("name").limit(2).aggregate(*pipeline)
assert list(data) == [
{"_id": p1.pk, "name": "ISABELLA LUANNA"},
{"_id": p3.pk, "name": "SANDRA MARA"},
]
# Make sure old interface works as expected with a 2-steps pipeline
pipeline = [{"$project": {"name": {"$toUpper": "$name"}}}, {"$limit": 1}]
data = Person.objects.order_by("name").limit(2).aggregate(*pipeline)
assert list(data) == [{"_id": p1.pk, "name": "ISABELLA LUANNA"}]
if __name__ == "__main__":
unittest.main()

View File

@ -1,6 +1,7 @@
import unittest
from bson.son import SON
import pytest
from mongoengine import *
from mongoengine.queryset import Q, transform
@ -13,23 +14,16 @@ class TestTransform(unittest.TestCase):
def test_transform_query(self):
"""Ensure that the _transform_query function operates correctly.
"""
self.assertEqual(
transform.query(name="test", age=30), {"name": "test", "age": 30}
)
self.assertEqual(transform.query(age__lt=30), {"age": {"$lt": 30}})
self.assertEqual(
transform.query(age__gt=20, age__lt=50), {"age": {"$gt": 20, "$lt": 50}}
)
self.assertEqual(
transform.query(age=20, age__gt=50),
{"$and": [{"age": {"$gt": 50}}, {"age": 20}]},
)
self.assertEqual(
transform.query(friend__age__gte=30), {"friend.age": {"$gte": 30}}
)
self.assertEqual(
transform.query(name__exists=True), {"name": {"$exists": True}}
)
assert transform.query(name="test", age=30) == {"name": "test", "age": 30}
assert transform.query(age__lt=30) == {"age": {"$lt": 30}}
assert transform.query(age__gt=20, age__lt=50) == {
"age": {"$gt": 20, "$lt": 50}
}
assert transform.query(age=20, age__gt=50) == {
"$and": [{"age": {"$gt": 50}}, {"age": 20}]
}
assert transform.query(friend__age__gte=30) == {"friend.age": {"$gte": 30}}
assert transform.query(name__exists=True) == {"name": {"$exists": True}}
def test_transform_update(self):
class LisDoc(Document):
@ -54,17 +48,17 @@ class TestTransform(unittest.TestCase):
("push", "$push"),
):
update = transform.update(DicDoc, **{"%s__dictField__test" % k: doc})
self.assertIsInstance(update[v]["dictField.test"], dict)
assert isinstance(update[v]["dictField.test"], dict)
# Update special cases
update = transform.update(DicDoc, unset__dictField__test=doc)
self.assertEqual(update["$unset"]["dictField.test"], 1)
assert update["$unset"]["dictField.test"] == 1
update = transform.update(DicDoc, pull__dictField__test=doc)
self.assertIsInstance(update["$pull"]["dictField"]["test"], dict)
assert isinstance(update["$pull"]["dictField"]["test"], dict)
update = transform.update(LisDoc, pull__foo__in=["a"])
self.assertEqual(update, {"$pull": {"foo": {"$in": ["a"]}}})
assert update == {"$pull": {"foo": {"$in": ["a"]}}}
def test_transform_update_push(self):
"""Ensure the differences in behvaior between 'push' and 'push_all'"""
@ -73,10 +67,10 @@ class TestTransform(unittest.TestCase):
tags = ListField(StringField())
update = transform.update(BlogPost, push__tags=["mongo", "db"])
self.assertEqual(update, {"$push": {"tags": ["mongo", "db"]}})
assert update == {"$push": {"tags": ["mongo", "db"]}}
update = transform.update(BlogPost, push_all__tags=["mongo", "db"])
self.assertEqual(update, {"$push": {"tags": {"$each": ["mongo", "db"]}}})
assert update == {"$push": {"tags": {"$each": ["mongo", "db"]}}}
def test_transform_update_no_operator_default_to_set(self):
"""Ensure the differences in behvaior between 'push' and 'push_all'"""
@ -85,7 +79,7 @@ class TestTransform(unittest.TestCase):
tags = ListField(StringField())
update = transform.update(BlogPost, tags=["mongo", "db"])
self.assertEqual(update, {"$set": {"tags": ["mongo", "db"]}})
assert update == {"$set": {"tags": ["mongo", "db"]}}
def test_query_field_name(self):
"""Ensure that the correct field name is used when querying.
@ -106,18 +100,18 @@ class TestTransform(unittest.TestCase):
post = BlogPost(**data)
post.save()
self.assertIn("postTitle", BlogPost.objects(title=data["title"])._query)
self.assertFalse("title" in BlogPost.objects(title=data["title"])._query)
self.assertEqual(BlogPost.objects(title=data["title"]).count(), 1)
assert "postTitle" in BlogPost.objects(title=data["title"])._query
assert not ("title" in BlogPost.objects(title=data["title"])._query)
assert BlogPost.objects(title=data["title"]).count() == 1
self.assertIn("_id", BlogPost.objects(pk=post.id)._query)
self.assertEqual(BlogPost.objects(pk=post.id).count(), 1)
assert "_id" in BlogPost.objects(pk=post.id)._query
assert BlogPost.objects(pk=post.id).count() == 1
self.assertIn(
"postComments.commentContent",
BlogPost.objects(comments__content="test")._query,
assert (
"postComments.commentContent"
in BlogPost.objects(comments__content="test")._query
)
self.assertEqual(BlogPost.objects(comments__content="test").count(), 1)
assert BlogPost.objects(comments__content="test").count() == 1
BlogPost.drop_collection()
@ -135,9 +129,9 @@ class TestTransform(unittest.TestCase):
post = BlogPost(**data)
post.save()
self.assertIn("_id", BlogPost.objects(pk=data["title"])._query)
self.assertIn("_id", BlogPost.objects(title=data["title"])._query)
self.assertEqual(BlogPost.objects(pk=data["title"]).count(), 1)
assert "_id" in BlogPost.objects(pk=data["title"])._query
assert "_id" in BlogPost.objects(title=data["title"])._query
assert BlogPost.objects(pk=data["title"]).count() == 1
BlogPost.drop_collection()
@ -163,7 +157,7 @@ class TestTransform(unittest.TestCase):
q2 = B.objects.filter(a__in=[a1, a2])
q2 = q2.filter(a=a1)._query
self.assertEqual(q1, q2)
assert q1 == q2
def test_raw_query_and_Q_objects(self):
"""
@ -179,11 +173,11 @@ class TestTransform(unittest.TestCase):
meta = {"allow_inheritance": False}
query = Foo.objects(__raw__={"$nor": [{"name": "bar"}]})._query
self.assertEqual(query, {"$nor": [{"name": "bar"}]})
assert query == {"$nor": [{"name": "bar"}]}
q1 = {"$or": [{"a": 1}, {"b": 1}]}
query = Foo.objects(Q(__raw__=q1) & Q(c=1))._query
self.assertEqual(query, {"$or": [{"a": 1}, {"b": 1}], "c": 1})
assert query == {"$or": [{"a": 1}, {"b": 1}], "c": 1}
def test_raw_and_merging(self):
class Doc(Document):
@ -200,51 +194,39 @@ class TestTransform(unittest.TestCase):
}
)._query
self.assertEqual(
raw_query,
{
"deleted": False,
"scraped": "yes",
"$nor": [
{"views.extracted": "no"},
{"attachments.views.extracted": "no"},
],
},
)
assert raw_query == {
"deleted": False,
"scraped": "yes",
"$nor": [{"views.extracted": "no"}, {"attachments.views.extracted": "no"}],
}
def test_geojson_PointField(self):
class Location(Document):
loc = PointField()
update = transform.update(Location, set__loc=[1, 2])
self.assertEqual(
update, {"$set": {"loc": {"type": "Point", "coordinates": [1, 2]}}}
)
assert update == {"$set": {"loc": {"type": "Point", "coordinates": [1, 2]}}}
update = transform.update(
Location, set__loc={"type": "Point", "coordinates": [1, 2]}
)
self.assertEqual(
update, {"$set": {"loc": {"type": "Point", "coordinates": [1, 2]}}}
)
assert update == {"$set": {"loc": {"type": "Point", "coordinates": [1, 2]}}}
def test_geojson_LineStringField(self):
class Location(Document):
line = LineStringField()
update = transform.update(Location, set__line=[[1, 2], [2, 2]])
self.assertEqual(
update,
{"$set": {"line": {"type": "LineString", "coordinates": [[1, 2], [2, 2]]}}},
)
assert update == {
"$set": {"line": {"type": "LineString", "coordinates": [[1, 2], [2, 2]]}}
}
update = transform.update(
Location, set__line={"type": "LineString", "coordinates": [[1, 2], [2, 2]]}
)
self.assertEqual(
update,
{"$set": {"line": {"type": "LineString", "coordinates": [[1, 2], [2, 2]]}}},
)
assert update == {
"$set": {"line": {"type": "LineString", "coordinates": [[1, 2], [2, 2]]}}
}
def test_geojson_PolygonField(self):
class Location(Document):
@ -253,17 +235,14 @@ class TestTransform(unittest.TestCase):
update = transform.update(
Location, set__poly=[[[40, 5], [40, 6], [41, 6], [40, 5]]]
)
self.assertEqual(
update,
{
"$set": {
"poly": {
"type": "Polygon",
"coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]],
}
assert update == {
"$set": {
"poly": {
"type": "Polygon",
"coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]],
}
},
)
}
}
update = transform.update(
Location,
@ -272,17 +251,14 @@ class TestTransform(unittest.TestCase):
"coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]],
},
)
self.assertEqual(
update,
{
"$set": {
"poly": {
"type": "Polygon",
"coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]],
}
assert update == {
"$set": {
"poly": {
"type": "Polygon",
"coordinates": [[[40, 5], [40, 6], [41, 6], [40, 5]]],
}
},
)
}
}
def test_type(self):
class Doc(Document):
@ -291,10 +267,10 @@ class TestTransform(unittest.TestCase):
Doc(df=True).save()
Doc(df=7).save()
Doc(df="df").save()
self.assertEqual(Doc.objects(df__type=1).count(), 0) # double
self.assertEqual(Doc.objects(df__type=8).count(), 1) # bool
self.assertEqual(Doc.objects(df__type=2).count(), 1) # str
self.assertEqual(Doc.objects(df__type=16).count(), 1) # int
assert Doc.objects(df__type=1).count() == 0 # double
assert Doc.objects(df__type=8).count() == 1 # bool
assert Doc.objects(df__type=2).count() == 1 # str
assert Doc.objects(df__type=16).count() == 1 # int
def test_last_field_name_like_operator(self):
class EmbeddedItem(EmbeddedDocument):
@ -309,12 +285,12 @@ class TestTransform(unittest.TestCase):
doc = Doc(item=EmbeddedItem(type="axe", name="Heroic axe"))
doc.save()
self.assertEqual(1, Doc.objects(item__type__="axe").count())
self.assertEqual(1, Doc.objects(item__name__="Heroic axe").count())
assert 1 == Doc.objects(item__type__="axe").count()
assert 1 == Doc.objects(item__name__="Heroic axe").count()
Doc.objects(id=doc.id).update(set__item__type__="sword")
self.assertEqual(1, Doc.objects(item__type__="sword").count())
self.assertEqual(0, Doc.objects(item__type__="axe").count())
assert 1 == Doc.objects(item__type__="sword").count()
assert 0 == Doc.objects(item__type__="axe").count()
def test_understandable_error_raised(self):
class Event(Document):
@ -324,7 +300,7 @@ class TestTransform(unittest.TestCase):
box = [(35.0, -125.0), (40.0, -100.0)]
# I *meant* to execute location__within_box=box
events = Event.objects(location__within=box)
with self.assertRaises(InvalidQueryError):
with pytest.raises(InvalidQueryError):
events.count()
def test_update_pull_for_list_fields(self):
@ -347,24 +323,20 @@ class TestTransform(unittest.TestCase):
word = Word(word="abc", index=1)
update = transform.update(MainDoc, pull__content__text=word)
self.assertEqual(
update, {"$pull": {"content.text": SON([("word", u"abc"), ("index", 1)])}}
)
assert update == {
"$pull": {"content.text": SON([("word", u"abc"), ("index", 1)])}
}
update = transform.update(MainDoc, pull__content__heading="xyz")
self.assertEqual(update, {"$pull": {"content.heading": "xyz"}})
assert update == {"$pull": {"content.heading": "xyz"}}
update = transform.update(MainDoc, pull__content__text__word__in=["foo", "bar"])
self.assertEqual(
update, {"$pull": {"content.text": {"word": {"$in": ["foo", "bar"]}}}}
)
assert update == {"$pull": {"content.text": {"word": {"$in": ["foo", "bar"]}}}}
update = transform.update(
MainDoc, pull__content__text__word__nin=["foo", "bar"]
)
self.assertEqual(
update, {"$pull": {"content.text": {"word": {"$nin": ["foo", "bar"]}}}}
)
assert update == {"$pull": {"content.text": {"word": {"$nin": ["foo", "bar"]}}}}
if __name__ == "__main__":

View File

@ -3,6 +3,7 @@ import re
import unittest
from bson import ObjectId
import pytest
from mongoengine import *
from mongoengine.errors import InvalidQueryError
@ -35,10 +36,10 @@ class TestQ(unittest.TestCase):
age = IntField()
query = {"$or": [{"age": {"$gte": 18}}, {"name": "test"}]}
self.assertEqual((q1 | q2 | q3 | q4 | q5).to_query(Person), query)
assert (q1 | q2 | q3 | q4 | q5).to_query(Person) == query
query = {"age": {"$gte": 18}, "name": "test"}
self.assertEqual((q1 & q2 & q3 & q4 & q5).to_query(Person), query)
assert (q1 & q2 & q3 & q4 & q5).to_query(Person) == query
def test_q_with_dbref(self):
"""Ensure Q objects handle DBRefs correctly"""
@ -53,8 +54,8 @@ class TestQ(unittest.TestCase):
user = User.objects.create()
Post.objects.create(created_user=user)
self.assertEqual(Post.objects.filter(created_user=user).count(), 1)
self.assertEqual(Post.objects.filter(Q(created_user=user)).count(), 1)
assert Post.objects.filter(created_user=user).count() == 1
assert Post.objects.filter(Q(created_user=user)).count() == 1
def test_and_combination(self):
"""Ensure that Q-objects correctly AND together.
@ -65,12 +66,10 @@ class TestQ(unittest.TestCase):
y = StringField()
query = (Q(x__lt=7) & Q(x__lt=3)).to_query(TestDoc)
self.assertEqual(query, {"$and": [{"x": {"$lt": 7}}, {"x": {"$lt": 3}}]})
assert query == {"$and": [{"x": {"$lt": 7}}, {"x": {"$lt": 3}}]}
query = (Q(y="a") & Q(x__lt=7) & Q(x__lt=3)).to_query(TestDoc)
self.assertEqual(
query, {"$and": [{"y": "a"}, {"x": {"$lt": 7}}, {"x": {"$lt": 3}}]}
)
assert query == {"$and": [{"y": "a"}, {"x": {"$lt": 7}}, {"x": {"$lt": 3}}]}
# Check normal cases work without an error
query = Q(x__lt=7) & Q(x__gt=3)
@ -78,7 +77,7 @@ class TestQ(unittest.TestCase):
q1 = Q(x__lt=7)
q2 = Q(x__gt=3)
query = (q1 & q2).to_query(TestDoc)
self.assertEqual(query, {"x": {"$lt": 7, "$gt": 3}})
assert query == {"x": {"$lt": 7, "$gt": 3}}
# More complex nested example
query = Q(x__lt=100) & Q(y__ne="NotMyString")
@ -87,7 +86,7 @@ class TestQ(unittest.TestCase):
"x": {"$lt": 100, "$gt": -100},
"y": {"$ne": "NotMyString", "$in": ["a", "b", "c"]},
}
self.assertEqual(query.to_query(TestDoc), mongo_query)
assert query.to_query(TestDoc) == mongo_query
def test_or_combination(self):
"""Ensure that Q-objects correctly OR together.
@ -99,7 +98,7 @@ class TestQ(unittest.TestCase):
q1 = Q(x__lt=3)
q2 = Q(x__gt=7)
query = (q1 | q2).to_query(TestDoc)
self.assertEqual(query, {"$or": [{"x": {"$lt": 3}}, {"x": {"$gt": 7}}]})
assert query == {"$or": [{"x": {"$lt": 3}}, {"x": {"$gt": 7}}]}
def test_and_or_combination(self):
"""Ensure that Q-objects handle ANDing ORed components.
@ -113,15 +112,12 @@ class TestQ(unittest.TestCase):
query = Q(x__gt=0) | Q(x__exists=False)
query &= Q(x__lt=100)
self.assertEqual(
query.to_query(TestDoc),
{
"$and": [
{"$or": [{"x": {"$gt": 0}}, {"x": {"$exists": False}}]},
{"x": {"$lt": 100}},
]
},
)
assert query.to_query(TestDoc) == {
"$and": [
{"$or": [{"x": {"$gt": 0}}, {"x": {"$exists": False}}]},
{"x": {"$lt": 100}},
]
}
q1 = Q(x__gt=0) | Q(x__exists=False)
q2 = Q(x__lt=100) | Q(y=True)
@ -131,16 +127,13 @@ class TestQ(unittest.TestCase):
TestDoc(x=10).save()
TestDoc(y=True).save()
self.assertEqual(
query,
{
"$and": [
{"$or": [{"x": {"$gt": 0}}, {"x": {"$exists": False}}]},
{"$or": [{"x": {"$lt": 100}}, {"y": True}]},
]
},
)
self.assertEqual(2, TestDoc.objects(q1 & q2).count())
assert query == {
"$and": [
{"$or": [{"x": {"$gt": 0}}, {"x": {"$exists": False}}]},
{"$or": [{"x": {"$lt": 100}}, {"y": True}]},
]
}
assert 2 == TestDoc.objects(q1 & q2).count()
def test_or_and_or_combination(self):
"""Ensure that Q-objects handle ORing ANDed ORed components. :)
@ -160,26 +153,23 @@ class TestQ(unittest.TestCase):
q2 = Q(x__lt=100) & (Q(y=False) | Q(y__exists=False))
query = (q1 | q2).to_query(TestDoc)
self.assertEqual(
query,
{
"$or": [
{
"$and": [
{"x": {"$gt": 0}},
{"$or": [{"y": True}, {"y": {"$exists": False}}]},
]
},
{
"$and": [
{"x": {"$lt": 100}},
{"$or": [{"y": False}, {"y": {"$exists": False}}]},
]
},
]
},
)
self.assertEqual(2, TestDoc.objects(q1 | q2).count())
assert query == {
"$or": [
{
"$and": [
{"x": {"$gt": 0}},
{"$or": [{"y": True}, {"y": {"$exists": False}}]},
]
},
{
"$and": [
{"x": {"$lt": 100}},
{"$or": [{"y": False}, {"y": {"$exists": False}}]},
]
},
]
}
assert 2 == TestDoc.objects(q1 | q2).count()
def test_multiple_occurence_in_field(self):
class Test(Document):
@ -192,8 +182,8 @@ class TestQ(unittest.TestCase):
q3 = q1 & q2
query = q3.to_query(Test)
self.assertEqual(query["$and"][0], q1.to_query(Test))
self.assertEqual(query["$and"][1], q2.to_query(Test))
assert query["$and"][0] == q1.to_query(Test)
assert query["$and"][1] == q2.to_query(Test)
def test_q_clone(self):
class TestDoc(Document):
@ -207,15 +197,15 @@ class TestQ(unittest.TestCase):
# Check normal cases work without an error
test = TestDoc.objects(Q(x__lt=7) & Q(x__gt=3))
self.assertEqual(test.count(), 3)
assert test.count() == 3
test2 = test.clone()
self.assertEqual(test2.count(), 3)
self.assertNotEqual(test2, test)
assert test2.count() == 3
assert test2 != test
test3 = test2.filter(x=6)
self.assertEqual(test3.count(), 1)
self.assertEqual(test.count(), 3)
assert test3.count() == 1
assert test.count() == 3
def test_q(self):
"""Ensure that Q objects may be used to query for documents.
@ -252,19 +242,19 @@ class TestQ(unittest.TestCase):
# Check ObjectId lookup works
obj = BlogPost.objects(id=post1.id).first()
self.assertEqual(obj, post1)
assert obj == post1
# Check Q object combination with one does not exist
q = BlogPost.objects(Q(title="Test 5") | Q(published=True))
posts = [post.id for post in q]
published_posts = (post2, post3)
self.assertTrue(all(obj.id in posts for obj in published_posts))
assert all(obj.id in posts for obj in published_posts)
q = BlogPost.objects(Q(title="Test 1") | Q(published=True))
posts = [post.id for post in q]
published_posts = (post1, post2, post3, post5, post6)
self.assertTrue(all(obj.id in posts for obj in published_posts))
assert all(obj.id in posts for obj in published_posts)
# Check Q object combination
date = datetime.datetime(2010, 1, 10)
@ -272,9 +262,9 @@ class TestQ(unittest.TestCase):
posts = [post.id for post in q]
published_posts = (post1, post2, post3, post4)
self.assertTrue(all(obj.id in posts for obj in published_posts))
assert all(obj.id in posts for obj in published_posts)
self.assertFalse(any(obj.id in posts for obj in [post5, post6]))
assert not any(obj.id in posts for obj in [post5, post6])
BlogPost.drop_collection()
@ -284,15 +274,15 @@ class TestQ(unittest.TestCase):
self.Person(name="user3", age=30).save()
self.Person(name="user4", age=40).save()
self.assertEqual(self.Person.objects(Q(age__in=[20])).count(), 2)
self.assertEqual(self.Person.objects(Q(age__in=[20, 30])).count(), 3)
assert self.Person.objects(Q(age__in=[20])).count() == 2
assert self.Person.objects(Q(age__in=[20, 30])).count() == 3
# Test invalid query objs
with self.assertRaises(InvalidQueryError):
with pytest.raises(InvalidQueryError):
self.Person.objects("user1")
# filter should fail, too
with self.assertRaises(InvalidQueryError):
with pytest.raises(InvalidQueryError):
self.Person.objects.filter("user1")
def test_q_regex(self):
@ -302,31 +292,31 @@ class TestQ(unittest.TestCase):
person.save()
obj = self.Person.objects(Q(name=re.compile("^Gui"))).first()
self.assertEqual(obj, person)
assert obj == person
obj = self.Person.objects(Q(name=re.compile("^gui"))).first()
self.assertEqual(obj, None)
assert obj is None
obj = self.Person.objects(Q(name=re.compile("^gui", re.I))).first()
self.assertEqual(obj, person)
assert obj == person
obj = self.Person.objects(Q(name__not=re.compile("^bob"))).first()
self.assertEqual(obj, person)
assert obj == person
obj = self.Person.objects(Q(name__not=re.compile("^Gui"))).first()
self.assertEqual(obj, None)
assert obj is None
def test_q_repr(self):
self.assertEqual(repr(Q()), "Q(**{})")
self.assertEqual(repr(Q(name="test")), "Q(**{'name': 'test'})")
assert repr(Q()) == "Q(**{})"
assert repr(Q(name="test")) == "Q(**{'name': 'test'})"
self.assertEqual(
repr(Q(name="test") & Q(age__gte=18)),
"(Q(**{'name': 'test'}) & Q(**{'age__gte': 18}))",
assert (
repr(Q(name="test") & Q(age__gte=18))
== "(Q(**{'name': 'test'}) & Q(**{'age__gte': 18}))"
)
self.assertEqual(
repr(Q(name="test") | Q(age__gte=18)),
"(Q(**{'name': 'test'}) | Q(**{'age__gte': 18}))",
assert (
repr(Q(name="test") | Q(age__gte=18))
== "(Q(**{'name': 'test'}) | Q(**{'age__gte': 18}))"
)
def test_q_lists(self):
@ -341,8 +331,8 @@ class TestQ(unittest.TestCase):
BlogPost(tags=["python", "mongo"]).save()
BlogPost(tags=["python"]).save()
self.assertEqual(BlogPost.objects(Q(tags="mongo")).count(), 1)
self.assertEqual(BlogPost.objects(Q(tags="python")).count(), 2)
assert BlogPost.objects(Q(tags="mongo")).count() == 1
assert BlogPost.objects(Q(tags="python")).count() == 2
BlogPost.drop_collection()
@ -355,12 +345,12 @@ class TestQ(unittest.TestCase):
pk = ObjectId()
User(email="example@example.com", pk=pk).save()
self.assertEqual(
1,
User.objects.filter(Q(email="example@example.com") | Q(name="John Doe"))
assert (
1
== User.objects.filter(Q(email="example@example.com") | Q(name="John Doe"))
.limit(2)
.filter(pk=pk)
.count(),
.count()
)
def test_chained_q_or_filtering(self):
@ -376,16 +366,58 @@ class TestQ(unittest.TestCase):
Item(postables=[Post(name="a"), Post(name="c")]).save()
Item(postables=[Post(name="a"), Post(name="b"), Post(name="c")]).save()
self.assertEqual(
Item.objects(Q(postables__name="a") & Q(postables__name="b")).count(), 2
assert (
Item.objects(Q(postables__name="a") & Q(postables__name="b")).count() == 2
)
self.assertEqual(
Item.objects.filter(postables__name="a")
.filter(postables__name="b")
.count(),
2,
assert (
Item.objects.filter(postables__name="a").filter(postables__name="b").count()
== 2
)
def test_equality(self):
assert Q(name="John") == Q(name="John")
assert Q() == Q()
def test_inequality(self):
assert Q(name="John") != Q(name="Ralph")
def test_operation_equality(self):
q1 = Q(name="John") | Q(title="Sir") & Q(surname="Paul")
q2 = Q(name="John") | Q(title="Sir") & Q(surname="Paul")
assert q1 == q2
def test_operation_inequality(self):
q1 = Q(name="John") | Q(title="Sir")
q2 = Q(title="Sir") | Q(name="John")
assert q1 != q2
def test_combine_and_empty(self):
q = Q(x=1)
assert q & Q() == q
assert Q() & q == q
def test_combine_and_both_empty(self):
assert Q() & Q() == Q()
def test_combine_or_empty(self):
q = Q(x=1)
assert q | Q() == q
assert Q() | q == q
def test_combine_or_both_empty(self):
assert Q() | Q() == Q()
def test_q_bool(self):
assert Q(name="John")
assert not Q()
def test_combine_bool(self):
assert not Q() & Q()
assert Q() & Q(name="John")
assert Q(name="John") & Q()
assert Q() | Q(name="John")
assert Q(name="John") | Q()
if __name__ == "__main__":
unittest.main()

9
tests/test_ci.py Normal file
View File

@ -0,0 +1,9 @@
def test_ci_placeholder():
# This empty test is used within the CI to
# setup the tox venv without running the test suite
# if we simply skip all test with pytest -k=wrong_pattern
# pytest command would return with exit_code=5 (i.e "no tests run")
# making travis fail
# this empty test is the recommended way to handle this
# as described in https://github.com/pytest-dev/pytest/issues/2393
pass

View File

@ -1,14 +1,16 @@
import unittest
from mongoengine.common import _import_class
import pytest
from mongoengine import Document
from mongoengine.common import _import_class
class TestCommon(unittest.TestCase):
class TestCommon:
def test__import_class(self):
doc_cls = _import_class("Document")
self.assertIs(doc_cls, Document)
assert doc_cls is Document
def test__import_class_raise_if_not_known(self):
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
_import_class("UnknownClass")

View File

@ -1,35 +1,32 @@
import datetime
from pymongo import MongoClient
from pymongo.errors import OperationFailure, InvalidName
from pymongo import ReadPreference
from bson.tz_util import utc
import pymongo
from mongoengine import Document
from pymongo import MongoClient, ReadPreference
from pymongo.errors import InvalidName, OperationFailure
import pytest
try:
import unittest2 as unittest
except ImportError:
import unittest
from nose.plugins.skip import SkipTest
import pymongo
from bson.tz_util import utc
from mongoengine import (
connect,
register_connection,
Document,
DateTimeField,
disconnect_all,
StringField,
)
import mongoengine.connection
from mongoengine import (
DateTimeField,
Document,
StringField,
connect,
disconnect_all,
register_connection,
)
from mongoengine.connection import (
ConnectionFailure,
get_db,
get_connection,
disconnect,
DEFAULT_DATABASE_NAME,
disconnect,
get_connection,
get_db,
)
@ -37,6 +34,18 @@ def get_tz_awareness(connection):
return connection.codec_options.tz_aware
try:
import mongomock
MONGOMOCK_INSTALLED = True
except ImportError:
MONGOMOCK_INSTALLED = False
require_mongomock = pytest.mark.skipif(
not MONGOMOCK_INSTALLED, reason="you need mongomock installed to run this testcase"
)
class ConnectionTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
@ -56,15 +65,15 @@ class ConnectionTest(unittest.TestCase):
connect("mongoenginetest")
conn = get_connection()
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
assert isinstance(conn, pymongo.mongo_client.MongoClient)
db = get_db()
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, "mongoenginetest")
assert isinstance(db, pymongo.database.Database)
assert db.name == "mongoenginetest"
connect("mongoenginetest2", alias="testdb")
conn = get_connection("testdb")
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
assert isinstance(conn, pymongo.mongo_client.MongoClient)
def test_connect_disconnect_works_properly(self):
class History1(Document):
@ -84,31 +93,27 @@ class ConnectionTest(unittest.TestCase):
h = History1(name="default").save()
h1 = History2(name="db1").save()
self.assertEqual(
list(History1.objects().as_pymongo()), [{"_id": h.id, "name": "default"}]
)
self.assertEqual(
list(History2.objects().as_pymongo()), [{"_id": h1.id, "name": "db1"}]
)
assert list(History1.objects().as_pymongo()) == [
{"_id": h.id, "name": "default"}
]
assert list(History2.objects().as_pymongo()) == [{"_id": h1.id, "name": "db1"}]
disconnect("db1")
disconnect("db2")
with self.assertRaises(ConnectionFailure):
with pytest.raises(ConnectionFailure):
list(History1.objects().as_pymongo())
with self.assertRaises(ConnectionFailure):
with pytest.raises(ConnectionFailure):
list(History2.objects().as_pymongo())
connect("db1", alias="db1")
connect("db2", alias="db2")
self.assertEqual(
list(History1.objects().as_pymongo()), [{"_id": h.id, "name": "default"}]
)
self.assertEqual(
list(History2.objects().as_pymongo()), [{"_id": h1.id, "name": "db1"}]
)
assert list(History1.objects().as_pymongo()) == [
{"_id": h.id, "name": "default"}
]
assert list(History2.objects().as_pymongo()) == [{"_id": h1.id, "name": "db1"}]
def test_connect_different_documents_to_different_database(self):
class History(Document):
@ -134,68 +139,64 @@ class ConnectionTest(unittest.TestCase):
h1 = History1(name="db1").save()
h2 = History2(name="db2").save()
self.assertEqual(History._collection.database.name, DEFAULT_DATABASE_NAME)
self.assertEqual(History1._collection.database.name, "db1")
self.assertEqual(History2._collection.database.name, "db2")
assert History._collection.database.name == DEFAULT_DATABASE_NAME
assert History1._collection.database.name == "db1"
assert History2._collection.database.name == "db2"
self.assertEqual(
list(History.objects().as_pymongo()), [{"_id": h.id, "name": "default"}]
)
self.assertEqual(
list(History1.objects().as_pymongo()), [{"_id": h1.id, "name": "db1"}]
)
self.assertEqual(
list(History2.objects().as_pymongo()), [{"_id": h2.id, "name": "db2"}]
)
assert list(History.objects().as_pymongo()) == [
{"_id": h.id, "name": "default"}
]
assert list(History1.objects().as_pymongo()) == [{"_id": h1.id, "name": "db1"}]
assert list(History2.objects().as_pymongo()) == [{"_id": h2.id, "name": "db2"}]
def test_connect_fails_if_connect_2_times_with_default_alias(self):
connect("mongoenginetest")
with self.assertRaises(ConnectionFailure) as ctx_err:
with pytest.raises(ConnectionFailure) as exc_info:
connect("mongoenginetest2")
self.assertEqual(
"A different connection with alias `default` was already registered. Use disconnect() first",
str(ctx_err.exception),
assert (
"A different connection with alias `default` was already registered. Use disconnect() first"
== str(exc_info.value)
)
def test_connect_fails_if_connect_2_times_with_custom_alias(self):
connect("mongoenginetest", alias="alias1")
with self.assertRaises(ConnectionFailure) as ctx_err:
with pytest.raises(ConnectionFailure) as exc_info:
connect("mongoenginetest2", alias="alias1")
self.assertEqual(
"A different connection with alias `alias1` was already registered. Use disconnect() first",
str(ctx_err.exception),
assert (
"A different connection with alias `alias1` was already registered. Use disconnect() first"
== str(exc_info.value)
)
def test_connect_fails_if_similar_connection_settings_arent_defined_the_same_way(
self
self,
):
"""Intended to keep the detecton function simple but robust"""
db_name = "mongoenginetest"
db_alias = "alias1"
connect(db=db_name, alias=db_alias, host="localhost", port=27017)
with self.assertRaises(ConnectionFailure):
with pytest.raises(ConnectionFailure):
connect(host="mongodb://localhost:27017/%s" % db_name, alias=db_alias)
def test_connect_passes_silently_connect_multiple_times_with_same_config(self):
# test default connection to `test`
connect()
connect()
self.assertEqual(len(mongoengine.connection._connections), 1)
assert len(mongoengine.connection._connections) == 1
connect("test01", alias="test01")
connect("test01", alias="test01")
self.assertEqual(len(mongoengine.connection._connections), 2)
assert len(mongoengine.connection._connections) == 2
connect(host="mongodb://localhost:27017/mongoenginetest02", alias="test02")
connect(host="mongodb://localhost:27017/mongoenginetest02", alias="test02")
self.assertEqual(len(mongoengine.connection._connections), 3)
assert len(mongoengine.connection._connections) == 3
def test_connect_with_invalid_db_name(self):
"""Ensure that connect() method fails fast if db name is invalid
"""
with self.assertRaises(InvalidName):
with pytest.raises(InvalidName):
connect("mongomock://localhost")
def test_connect_with_db_name_external(self):
@ -205,38 +206,34 @@ class ConnectionTest(unittest.TestCase):
connect("$external")
conn = get_connection()
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
assert isinstance(conn, pymongo.mongo_client.MongoClient)
db = get_db()
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, "$external")
assert isinstance(db, pymongo.database.Database)
assert db.name == "$external"
connect("$external", alias="testdb")
conn = get_connection("testdb")
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
assert isinstance(conn, pymongo.mongo_client.MongoClient)
def test_connect_with_invalid_db_name_type(self):
"""Ensure that connect() method fails fast if db name has invalid type
"""
with self.assertRaises(TypeError):
with pytest.raises(TypeError):
non_string_db_name = ["e. g. list instead of a string"]
connect(non_string_db_name)
@require_mongomock
def test_connect_in_mocking(self):
"""Ensure that the connect() method works properly in mocking.
"""
try:
import mongomock
except ImportError:
raise SkipTest("you need mongomock installed to run this testcase")
connect("mongoenginetest", host="mongomock://localhost")
conn = get_connection()
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect("mongoenginetest2", host="mongomock://localhost", alias="testdb2")
conn = get_connection("testdb2")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect(
"mongoenginetest3",
@ -245,11 +242,11 @@ class ConnectionTest(unittest.TestCase):
alias="testdb3",
)
conn = get_connection("testdb3")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect("mongoenginetest4", is_mock=True, alias="testdb4")
conn = get_connection("testdb4")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect(
host="mongodb://localhost:27017/mongoenginetest5",
@ -257,11 +254,11 @@ class ConnectionTest(unittest.TestCase):
alias="testdb5",
)
conn = get_connection("testdb5")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect(host="mongomock://localhost:27017/mongoenginetest6", alias="testdb6")
conn = get_connection("testdb6")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect(
host="mongomock://localhost:27017/mongoenginetest7",
@ -269,16 +266,12 @@ class ConnectionTest(unittest.TestCase):
alias="testdb7",
)
conn = get_connection("testdb7")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
@require_mongomock
def test_default_database_with_mocking(self):
"""Ensure that the default database is correctly set when using mongomock.
"""
try:
import mongomock
except ImportError:
raise SkipTest("you need mongomock installed to run this testcase")
disconnect_all()
class SomeDocument(Document):
@ -288,37 +281,33 @@ class ConnectionTest(unittest.TestCase):
some_document = SomeDocument()
# database won't exist until we save a document
some_document.save()
self.assertEqual(conn.get_default_database().name, "mongoenginetest")
self.assertEqual(conn.database_names()[0], "mongoenginetest")
assert conn.get_default_database().name == "mongoenginetest"
assert conn.database_names()[0] == "mongoenginetest"
@require_mongomock
def test_connect_with_host_list(self):
"""Ensure that the connect() method works when host is a list
Uses mongomock to test w/o needing multiple mongod/mongos processes
"""
try:
import mongomock
except ImportError:
raise SkipTest("you need mongomock installed to run this testcase")
connect(host=["mongomock://localhost"])
conn = get_connection()
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect(host=["mongodb://localhost"], is_mock=True, alias="testdb2")
conn = get_connection("testdb2")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect(host=["localhost"], is_mock=True, alias="testdb3")
conn = get_connection("testdb3")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect(
host=["mongomock://localhost:27017", "mongomock://localhost:27018"],
alias="testdb4",
)
conn = get_connection("testdb4")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect(
host=["mongodb://localhost:27017", "mongodb://localhost:27018"],
@ -326,13 +315,13 @@ class ConnectionTest(unittest.TestCase):
alias="testdb5",
)
conn = get_connection("testdb5")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
connect(
host=["localhost:27017", "localhost:27018"], is_mock=True, alias="testdb6"
)
conn = get_connection("testdb6")
self.assertIsInstance(conn, mongomock.MongoClient)
assert isinstance(conn, mongomock.MongoClient)
def test_disconnect_cleans_globals(self):
"""Ensure that the disconnect() method cleans the globals objects"""
@ -342,20 +331,20 @@ class ConnectionTest(unittest.TestCase):
connect("mongoenginetest")
self.assertEqual(len(connections), 1)
self.assertEqual(len(dbs), 0)
self.assertEqual(len(connection_settings), 1)
assert len(connections) == 1
assert len(dbs) == 0
assert len(connection_settings) == 1
class TestDoc(Document):
pass
TestDoc.drop_collection() # triggers the db
self.assertEqual(len(dbs), 1)
assert len(dbs) == 1
disconnect()
self.assertEqual(len(connections), 0)
self.assertEqual(len(dbs), 0)
self.assertEqual(len(connection_settings), 0)
assert len(connections) == 0
assert len(dbs) == 0
assert len(connection_settings) == 0
def test_disconnect_cleans_cached_collection_attribute_in_document(self):
"""Ensure that the disconnect() method works properly"""
@ -364,22 +353,20 @@ class ConnectionTest(unittest.TestCase):
class History(Document):
pass
self.assertIsNone(History._collection)
assert History._collection is None
History.drop_collection()
History.objects.first() # will trigger the caching of _collection attribute
self.assertIsNotNone(History._collection)
assert History._collection is not None
disconnect()
self.assertIsNone(History._collection)
assert History._collection is None
with self.assertRaises(ConnectionFailure) as ctx_err:
with pytest.raises(ConnectionFailure) as exc_info:
History.objects.first()
self.assertEqual(
"You have not defined a default connection", str(ctx_err.exception)
)
assert "You have not defined a default connection" == str(exc_info.value)
def test_connect_disconnect_works_on_same_document(self):
"""Ensure that the connect/disconnect works properly with a single Document"""
@ -401,7 +388,7 @@ class ConnectionTest(unittest.TestCase):
disconnect()
# Make sure save doesnt work at this stage
with self.assertRaises(ConnectionFailure):
with pytest.raises(ConnectionFailure):
User(name="Wont work").save()
# Save in db2
@ -410,13 +397,13 @@ class ConnectionTest(unittest.TestCase):
disconnect()
db1_users = list(client[db1].user.find())
self.assertEqual(db1_users, [{"_id": user1.id, "name": "John is in db1"}])
assert db1_users == [{"_id": user1.id, "name": "John is in db1"}]
db2_users = list(client[db2].user.find())
self.assertEqual(db2_users, [{"_id": user2.id, "name": "Bob is in db2"}])
assert db2_users == [{"_id": user2.id, "name": "Bob is in db2"}]
def test_disconnect_silently_pass_if_alias_does_not_exist(self):
connections = mongoengine.connection._connections
self.assertEqual(len(connections), 0)
assert len(connections) == 0
disconnect(alias="not_exist")
def test_disconnect_all(self):
@ -439,26 +426,26 @@ class ConnectionTest(unittest.TestCase):
History1.drop_collection()
History1.objects.first()
self.assertIsNotNone(History._collection)
self.assertIsNotNone(History1._collection)
assert History._collection is not None
assert History1._collection is not None
self.assertEqual(len(connections), 2)
self.assertEqual(len(dbs), 2)
self.assertEqual(len(connection_settings), 2)
assert len(connections) == 2
assert len(dbs) == 2
assert len(connection_settings) == 2
disconnect_all()
self.assertIsNone(History._collection)
self.assertIsNone(History1._collection)
assert History._collection is None
assert History1._collection is None
self.assertEqual(len(connections), 0)
self.assertEqual(len(dbs), 0)
self.assertEqual(len(connection_settings), 0)
assert len(connections) == 0
assert len(dbs) == 0
assert len(connection_settings) == 0
with self.assertRaises(ConnectionFailure):
with pytest.raises(ConnectionFailure):
History.objects.first()
with self.assertRaises(ConnectionFailure):
with pytest.raises(ConnectionFailure):
History1.objects.first()
def test_disconnect_all_silently_pass_if_no_connection_exist(self):
@ -475,7 +462,7 @@ class ConnectionTest(unittest.TestCase):
expected_connection.server_info()
self.assertEqual(expected_connection, actual_connection)
assert expected_connection == actual_connection
def test_connect_uri(self):
"""Ensure that the connect() method works properly with URIs."""
@ -492,11 +479,11 @@ class ConnectionTest(unittest.TestCase):
)
conn = get_connection()
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
assert isinstance(conn, pymongo.mongo_client.MongoClient)
db = get_db()
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, "mongoenginetest")
assert isinstance(db, pymongo.database.Database)
assert db.name == "mongoenginetest"
c.admin.system.users.delete_many({})
c.mongoenginetest.system.users.delete_many({})
@ -508,11 +495,11 @@ class ConnectionTest(unittest.TestCase):
connect("mongoenginetest", host="mongodb://localhost/")
conn = get_connection()
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
assert isinstance(conn, pymongo.mongo_client.MongoClient)
db = get_db()
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, "mongoenginetest")
assert isinstance(db, pymongo.database.Database)
assert db.name == "mongoenginetest"
def test_connect_uri_default_db(self):
"""Ensure connect() defaults to the right database name if
@ -521,11 +508,11 @@ class ConnectionTest(unittest.TestCase):
connect(host="mongodb://localhost/")
conn = get_connection()
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
assert isinstance(conn, pymongo.mongo_client.MongoClient)
db = get_db()
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, "test")
assert isinstance(db, pymongo.database.Database)
assert db.name == "test"
def test_uri_without_credentials_doesnt_override_conn_settings(self):
"""Ensure connect() uses the username & password params if the URI
@ -538,7 +525,8 @@ class ConnectionTest(unittest.TestCase):
# OperationFailure means that mongoengine attempted authentication
# w/ the provided username/password and failed - that's the desired
# behavior. If the MongoDB URI would override the credentials
self.assertRaises(OperationFailure, get_db)
with pytest.raises(OperationFailure):
get_db()
def test_connect_uri_with_authsource(self):
"""Ensure that the connect() method works well with `authSource`
@ -556,7 +544,8 @@ class ConnectionTest(unittest.TestCase):
alias="test1",
host="mongodb://username2:password@localhost/mongoenginetest",
)
self.assertRaises(OperationFailure, test_conn.server_info)
with pytest.raises(OperationFailure):
test_conn.server_info()
# Authentication succeeds with "authSource"
authd_conn = connect(
@ -568,8 +557,8 @@ class ConnectionTest(unittest.TestCase):
),
)
db = get_db("test2")
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, "mongoenginetest")
assert isinstance(db, pymongo.database.Database)
assert db.name == "mongoenginetest"
# Clear all users
authd_conn.admin.system.users.delete_many({})
@ -579,13 +568,14 @@ class ConnectionTest(unittest.TestCase):
"""
register_connection("testdb", "mongoenginetest2")
self.assertRaises(ConnectionFailure, get_connection)
with pytest.raises(ConnectionFailure):
get_connection()
conn = get_connection("testdb")
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
assert isinstance(conn, pymongo.mongo_client.MongoClient)
db = get_db("testdb")
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, "mongoenginetest2")
assert isinstance(db, pymongo.database.Database)
assert db.name == "mongoenginetest2"
def test_register_connection_defaults(self):
"""Ensure that defaults are used when the host and port are None.
@ -593,18 +583,18 @@ class ConnectionTest(unittest.TestCase):
register_connection("testdb", "mongoenginetest", host=None, port=None)
conn = get_connection("testdb")
self.assertIsInstance(conn, pymongo.mongo_client.MongoClient)
assert isinstance(conn, pymongo.mongo_client.MongoClient)
def test_connection_kwargs(self):
"""Ensure that connection kwargs get passed to pymongo."""
connect("mongoenginetest", alias="t1", tz_aware=True)
conn = get_connection("t1")
self.assertTrue(get_tz_awareness(conn))
assert get_tz_awareness(conn)
connect("mongoenginetest2", alias="t2")
conn = get_connection("t2")
self.assertFalse(get_tz_awareness(conn))
assert not get_tz_awareness(conn)
def test_connection_pool_via_kwarg(self):
"""Ensure we can specify a max connection pool size using
@ -615,7 +605,7 @@ class ConnectionTest(unittest.TestCase):
conn = connect(
"mongoenginetest", alias="max_pool_size_via_kwarg", **pool_size_kwargs
)
self.assertEqual(conn.max_pool_size, 100)
assert conn.max_pool_size == 100
def test_connection_pool_via_uri(self):
"""Ensure we can specify a max connection pool size using
@ -625,16 +615,18 @@ class ConnectionTest(unittest.TestCase):
host="mongodb://localhost/test?maxpoolsize=100",
alias="max_pool_size_via_uri",
)
self.assertEqual(conn.max_pool_size, 100)
assert conn.max_pool_size == 100
def test_write_concern(self):
"""Ensure write concern can be specified in connect() via
a kwarg or as part of the connection URI.
"""
conn1 = connect(alias="conn1", host="mongodb://localhost/testing?w=1&j=true")
conn2 = connect("testing", alias="conn2", w=1, j=True)
self.assertEqual(conn1.write_concern.document, {"w": 1, "j": True})
self.assertEqual(conn2.write_concern.document, {"w": 1, "j": True})
conn1 = connect(
alias="conn1", host="mongodb://localhost/testing?w=1&journal=true"
)
conn2 = connect("testing", alias="conn2", w=1, journal=True)
assert conn1.write_concern.document == {"w": 1, "j": True}
assert conn2.write_concern.document == {"w": 1, "j": True}
def test_connect_with_replicaset_via_uri(self):
"""Ensure connect() works when specifying a replicaSet via the
@ -642,18 +634,18 @@ class ConnectionTest(unittest.TestCase):
"""
c = connect(host="mongodb://localhost/test?replicaSet=local-rs")
db = get_db()
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, "test")
assert isinstance(db, pymongo.database.Database)
assert db.name == "test"
def test_connect_with_replicaset_via_kwargs(self):
"""Ensure connect() works when specifying a replicaSet via the
connection kwargs
"""
c = connect(replicaset="local-rs")
self.assertEqual(c._MongoClient__options.replica_set_name, "local-rs")
assert c._MongoClient__options.replica_set_name == "local-rs"
db = get_db()
self.assertIsInstance(db, pymongo.database.Database)
self.assertEqual(db.name, "test")
assert isinstance(db, pymongo.database.Database)
assert db.name == "test"
def test_connect_tz_aware(self):
connect("mongoenginetest", tz_aware=True)
@ -666,13 +658,13 @@ class ConnectionTest(unittest.TestCase):
DateDoc(the_date=d).save()
date_doc = DateDoc.objects.first()
self.assertEqual(d, date_doc.the_date)
assert d == date_doc.the_date
def test_read_preference_from_parse(self):
conn = connect(
host="mongodb://a1.vpc,a2.vpc,a3.vpc/prod?readPreference=secondaryPreferred"
)
self.assertEqual(conn.read_preference, ReadPreference.SECONDARY_PREFERRED)
assert conn.read_preference == ReadPreference.SECONDARY_PREFERRED
def test_multiple_connection_settings(self):
connect("mongoenginetest", alias="t1", host="localhost")
@ -680,27 +672,27 @@ class ConnectionTest(unittest.TestCase):
connect("mongoenginetest2", alias="t2", host="127.0.0.1")
mongo_connections = mongoengine.connection._connections
self.assertEqual(len(mongo_connections.items()), 2)
self.assertIn("t1", mongo_connections.keys())
self.assertIn("t2", mongo_connections.keys())
assert len(mongo_connections.items()) == 2
assert "t1" in mongo_connections.keys()
assert "t2" in mongo_connections.keys()
# Handle PyMongo 3+ Async Connection
# Ensure we are connected, throws ServerSelectionTimeoutError otherwise.
# Purposely not catching exception to fail test if thrown.
mongo_connections["t1"].server_info()
mongo_connections["t2"].server_info()
self.assertEqual(mongo_connections["t1"].address[0], "localhost")
self.assertEqual(mongo_connections["t2"].address[0], "127.0.0.1")
assert mongo_connections["t1"].address[0] == "localhost"
assert mongo_connections["t2"].address[0] == "127.0.0.1"
def test_connect_2_databases_uses_same_client_if_only_dbname_differs(self):
c1 = connect(alias="testdb1", db="testdb1")
c2 = connect(alias="testdb2", db="testdb2")
self.assertIs(c1, c2)
assert c1 is c2
def test_connect_2_databases_uses_different_client_if_different_parameters(self):
c1 = connect(alias="testdb1", db="testdb1", username="u1")
c2 = connect(alias="testdb2", db="testdb2", username="u2")
self.assertIsNot(c1, c2)
assert c1 is not c2
if __name__ == "__main__":

View File

@ -1,18 +1,20 @@
import unittest
import pytest
from mongoengine import *
from mongoengine.connection import get_db
from mongoengine.context_managers import (
switch_db,
switch_collection,
no_sub_classes,
no_dereference,
no_sub_classes,
query_counter,
switch_collection,
switch_db,
)
from mongoengine.pymongo_support import count_documents
class ContextManagersTest(unittest.TestCase):
class TestContextManagers:
def test_switch_db_context_manager(self):
connect("mongoenginetest")
register_connection("testdb-1", "mongoenginetest2")
@ -23,20 +25,20 @@ class ContextManagersTest(unittest.TestCase):
Group.drop_collection()
Group(name="hello - default").save()
self.assertEqual(1, Group.objects.count())
assert 1 == Group.objects.count()
with switch_db(Group, "testdb-1") as Group:
self.assertEqual(0, Group.objects.count())
assert 0 == Group.objects.count()
Group(name="hello").save()
self.assertEqual(1, Group.objects.count())
assert 1 == Group.objects.count()
Group.drop_collection()
self.assertEqual(0, Group.objects.count())
assert 0 == Group.objects.count()
self.assertEqual(1, Group.objects.count())
assert 1 == Group.objects.count()
def test_switch_collection_context_manager(self):
connect("mongoenginetest")
@ -51,20 +53,20 @@ class ContextManagersTest(unittest.TestCase):
Group.drop_collection() # drops in group1
Group(name="hello - group").save()
self.assertEqual(1, Group.objects.count())
assert 1 == Group.objects.count()
with switch_collection(Group, "group1") as Group:
self.assertEqual(0, Group.objects.count())
assert 0 == Group.objects.count()
Group(name="hello - group1").save()
self.assertEqual(1, Group.objects.count())
assert 1 == Group.objects.count()
Group.drop_collection()
self.assertEqual(0, Group.objects.count())
assert 0 == Group.objects.count()
self.assertEqual(1, Group.objects.count())
assert 1 == Group.objects.count()
def test_no_dereference_context_manager_object_id(self):
"""Ensure that DBRef items in ListFields aren't dereferenced.
@ -89,20 +91,20 @@ class ContextManagersTest(unittest.TestCase):
Group(ref=user, members=User.objects, generic=user).save()
with no_dereference(Group) as NoDeRefGroup:
self.assertTrue(Group._fields["members"]._auto_dereference)
self.assertFalse(NoDeRefGroup._fields["members"]._auto_dereference)
assert Group._fields["members"]._auto_dereference
assert not NoDeRefGroup._fields["members"]._auto_dereference
with no_dereference(Group) as Group:
group = Group.objects.first()
for m in group.members:
self.assertNotIsInstance(m, User)
self.assertNotIsInstance(group.ref, User)
self.assertNotIsInstance(group.generic, User)
assert not isinstance(m, User)
assert not isinstance(group.ref, User)
assert not isinstance(group.generic, User)
for m in group.members:
self.assertIsInstance(m, User)
self.assertIsInstance(group.ref, User)
self.assertIsInstance(group.generic, User)
assert isinstance(m, User)
assert isinstance(group.ref, User)
assert isinstance(group.generic, User)
def test_no_dereference_context_manager_dbref(self):
"""Ensure that DBRef items in ListFields aren't dereferenced.
@ -127,18 +129,18 @@ class ContextManagersTest(unittest.TestCase):
Group(ref=user, members=User.objects, generic=user).save()
with no_dereference(Group) as NoDeRefGroup:
self.assertTrue(Group._fields["members"]._auto_dereference)
self.assertFalse(NoDeRefGroup._fields["members"]._auto_dereference)
assert Group._fields["members"]._auto_dereference
assert not NoDeRefGroup._fields["members"]._auto_dereference
with no_dereference(Group) as Group:
group = Group.objects.first()
self.assertTrue(all([not isinstance(m, User) for m in group.members]))
self.assertNotIsInstance(group.ref, User)
self.assertNotIsInstance(group.generic, User)
assert all([not isinstance(m, User) for m in group.members])
assert not isinstance(group.ref, User)
assert not isinstance(group.generic, User)
self.assertTrue(all([isinstance(m, User) for m in group.members]))
self.assertIsInstance(group.ref, User)
self.assertIsInstance(group.generic, User)
assert all([isinstance(m, User) for m in group.members])
assert isinstance(group.ref, User)
assert isinstance(group.generic, User)
def test_no_sub_classes(self):
class A(Document):
@ -159,32 +161,32 @@ class ContextManagersTest(unittest.TestCase):
B(x=30).save()
C(x=40).save()
self.assertEqual(A.objects.count(), 5)
self.assertEqual(B.objects.count(), 3)
self.assertEqual(C.objects.count(), 1)
assert A.objects.count() == 5
assert B.objects.count() == 3
assert C.objects.count() == 1
with no_sub_classes(A):
self.assertEqual(A.objects.count(), 2)
assert A.objects.count() == 2
for obj in A.objects:
self.assertEqual(obj.__class__, A)
assert obj.__class__ == A
with no_sub_classes(B):
self.assertEqual(B.objects.count(), 2)
assert B.objects.count() == 2
for obj in B.objects:
self.assertEqual(obj.__class__, B)
assert obj.__class__ == B
with no_sub_classes(C):
self.assertEqual(C.objects.count(), 1)
assert C.objects.count() == 1
for obj in C.objects:
self.assertEqual(obj.__class__, C)
assert obj.__class__ == C
# Confirm context manager exit correctly
self.assertEqual(A.objects.count(), 5)
self.assertEqual(B.objects.count(), 3)
self.assertEqual(C.objects.count(), 1)
assert A.objects.count() == 5
assert B.objects.count() == 3
assert C.objects.count() == 1
def test_no_sub_classes_modification_to_document_class_are_temporary(self):
class A(Document):
@ -194,27 +196,26 @@ class ContextManagersTest(unittest.TestCase):
class B(A):
z = IntField()
self.assertEqual(A._subclasses, ("A", "A.B"))
assert A._subclasses == ("A", "A.B")
with no_sub_classes(A):
self.assertEqual(A._subclasses, ("A",))
self.assertEqual(A._subclasses, ("A", "A.B"))
assert A._subclasses == ("A",)
assert A._subclasses == ("A", "A.B")
self.assertEqual(B._subclasses, ("A.B",))
assert B._subclasses == ("A.B",)
with no_sub_classes(B):
self.assertEqual(B._subclasses, ("A.B",))
self.assertEqual(B._subclasses, ("A.B",))
assert B._subclasses == ("A.B",)
assert B._subclasses == ("A.B",)
def test_no_subclass_context_manager_does_not_swallow_exception(self):
class User(Document):
name = StringField()
with self.assertRaises(TypeError):
with pytest.raises(TypeError):
with no_sub_classes(User):
raise TypeError()
def test_query_counter_does_not_swallow_exception(self):
with self.assertRaises(TypeError):
with pytest.raises(TypeError):
with query_counter() as q:
raise TypeError()
@ -227,10 +228,10 @@ class ContextManagersTest(unittest.TestCase):
try:
NEW_LEVEL = 1
db.set_profiling_level(NEW_LEVEL)
self.assertEqual(db.profiling_level(), NEW_LEVEL)
assert db.profiling_level() == NEW_LEVEL
with query_counter() as q:
self.assertEqual(db.profiling_level(), 2)
self.assertEqual(db.profiling_level(), NEW_LEVEL)
assert db.profiling_level() == 2
assert db.profiling_level() == NEW_LEVEL
except Exception:
db.set_profiling_level(
initial_profiling_level
@ -255,33 +256,77 @@ class ContextManagersTest(unittest.TestCase):
counter = 0
with query_counter() as q:
self.assertEqual(q, counter)
self.assertEqual(
q, counter
) # Ensures previous count query did not get counted
assert q == counter
assert q == counter # Ensures previous count query did not get counted
for _ in range(10):
issue_1_insert_query()
counter += 1
self.assertEqual(q, counter)
assert q == counter
for _ in range(4):
issue_1_find_query()
counter += 1
self.assertEqual(q, counter)
assert q == counter
for _ in range(3):
issue_1_count_query()
counter += 1
self.assertEqual(q, counter)
assert q == counter
self.assertEqual(int(q), counter) # test __int__
self.assertEqual(repr(q), str(int(q))) # test __repr__
self.assertGreater(q, -1) # test __gt__
self.assertGreaterEqual(q, int(q)) # test __gte__
self.assertNotEqual(q, -1)
self.assertLess(q, 1000)
self.assertLessEqual(q, int(q))
assert int(q) == counter # test __int__
assert repr(q) == str(int(q)) # test __repr__
assert q > -1 # test __gt__
assert q >= int(q) # test __gte__
assert q != -1
assert q < 1000
assert q <= int(q)
def test_query_counter_alias(self):
"""query_counter works properly with db aliases?"""
# Register a connection with db_alias testdb-1
register_connection("testdb-1", "mongoenginetest2")
class A(Document):
"""Uses default db_alias"""
name = StringField()
class B(Document):
"""Uses testdb-1 db_alias"""
name = StringField()
meta = {"db_alias": "testdb-1"}
A.drop_collection()
B.drop_collection()
with query_counter() as q:
assert q == 0
A.objects.create(name="A")
assert q == 1
a = A.objects.first()
assert q == 2
a.name = "Test A"
a.save()
assert q == 3
# querying the other db should'nt alter the counter
B.objects().first()
assert q == 3
with query_counter(alias="testdb-1") as q:
assert q == 0
B.objects.create(name="B")
assert q == 1
b = B.objects.first()
assert q == 2
b.name = "Test B"
b.save()
assert b.name == "Test B"
assert q == 3
# querying the other db should'nt alter the counter
A.objects().first()
assert q == 3
def test_query_counter_counts_getmore_queries(self):
connect("mongoenginetest")
@ -296,9 +341,9 @@ class ContextManagersTest(unittest.TestCase):
) # first batch of documents contains 101 documents
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
list(collection.find())
self.assertEqual(q, 2) # 1st select + 1 getmore
assert q == 2 # 1st select + 1 getmore
def test_query_counter_ignores_particular_queries(self):
connect("mongoenginetest")
@ -308,18 +353,18 @@ class ContextManagersTest(unittest.TestCase):
collection.insert_many([{"test": "garbage %s" % i} for i in range(10)])
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
cursor = collection.find()
self.assertEqual(q, 0) # cursor wasn't opened yet
assert q == 0 # cursor wasn't opened yet
_ = next(cursor) # opens the cursor and fires the find query
self.assertEqual(q, 1)
assert q == 1
cursor.close() # issues a `killcursors` query that is ignored by the context
self.assertEqual(q, 1)
assert q == 1
_ = (
db.system.indexes.find_one()
) # queries on db.system.indexes are ignored as well
self.assertEqual(q, 1)
assert q == 1
if __name__ == "__main__":

View File

@ -1,8 +1,10 @@
import unittest
import pytest
from six import iterkeys
from mongoengine import Document
from mongoengine.base.datastructures import StrictDict, BaseList, BaseDict
from mongoengine.base.datastructures import BaseDict, BaseList, StrictDict
class DocumentStub(object):
@ -13,15 +15,15 @@ class DocumentStub(object):
self._changed_fields.append(key)
class TestBaseDict(unittest.TestCase):
class TestBaseDict:
@staticmethod
def _get_basedict(dict_items):
"""Get a BaseList bound to a fake document instance"""
fake_doc = DocumentStub()
base_list = BaseDict(dict_items, instance=None, name="my_name")
base_list._instance = (
fake_doc
) # hack to inject the mock, it does not work in the constructor
fake_doc # hack to inject the mock, it does not work in the constructor
)
return base_list
def test___init___(self):
@ -31,48 +33,48 @@ class TestBaseDict(unittest.TestCase):
dict_items = {"k": "v"}
doc = MyDoc()
base_dict = BaseDict(dict_items, instance=doc, name="my_name")
self.assertIsInstance(base_dict._instance, Document)
self.assertEqual(base_dict._name, "my_name")
self.assertEqual(base_dict, dict_items)
assert isinstance(base_dict._instance, Document)
assert base_dict._name == "my_name"
assert base_dict == dict_items
def test_setdefault_calls_mark_as_changed(self):
base_dict = self._get_basedict({})
base_dict.setdefault("k", "v")
self.assertEqual(base_dict._instance._changed_fields, [base_dict._name])
assert base_dict._instance._changed_fields == [base_dict._name]
def test_popitems_calls_mark_as_changed(self):
base_dict = self._get_basedict({"k": "v"})
self.assertEqual(base_dict.popitem(), ("k", "v"))
self.assertEqual(base_dict._instance._changed_fields, [base_dict._name])
self.assertFalse(base_dict)
assert base_dict.popitem() == ("k", "v")
assert base_dict._instance._changed_fields == [base_dict._name]
assert not base_dict
def test_pop_calls_mark_as_changed(self):
base_dict = self._get_basedict({"k": "v"})
self.assertEqual(base_dict.pop("k"), "v")
self.assertEqual(base_dict._instance._changed_fields, [base_dict._name])
self.assertFalse(base_dict)
assert base_dict.pop("k") == "v"
assert base_dict._instance._changed_fields == [base_dict._name]
assert not base_dict
def test_pop_calls_does_not_mark_as_changed_when_it_fails(self):
base_dict = self._get_basedict({"k": "v"})
with self.assertRaises(KeyError):
with pytest.raises(KeyError):
base_dict.pop("X")
self.assertFalse(base_dict._instance._changed_fields)
assert not base_dict._instance._changed_fields
def test_clear_calls_mark_as_changed(self):
base_dict = self._get_basedict({"k": "v"})
base_dict.clear()
self.assertEqual(base_dict._instance._changed_fields, ["my_name"])
self.assertEqual(base_dict, {})
assert base_dict._instance._changed_fields == ["my_name"]
assert base_dict == {}
def test___delitem___calls_mark_as_changed(self):
base_dict = self._get_basedict({"k": "v"})
del base_dict["k"]
self.assertEqual(base_dict._instance._changed_fields, ["my_name.k"])
self.assertEqual(base_dict, {})
assert base_dict._instance._changed_fields == ["my_name.k"]
assert base_dict == {}
def test___getitem____KeyError(self):
base_dict = self._get_basedict({})
with self.assertRaises(KeyError):
with pytest.raises(KeyError):
base_dict["new"]
def test___getitem____simple_value(self):
@ -82,62 +84,62 @@ class TestBaseDict(unittest.TestCase):
def test___getitem____sublist_gets_converted_to_BaseList(self):
base_dict = self._get_basedict({"k": [0, 1, 2]})
sub_list = base_dict["k"]
self.assertEqual(sub_list, [0, 1, 2])
self.assertIsInstance(sub_list, BaseList)
self.assertIs(sub_list._instance, base_dict._instance)
self.assertEqual(sub_list._name, "my_name.k")
self.assertEqual(base_dict._instance._changed_fields, [])
assert sub_list == [0, 1, 2]
assert isinstance(sub_list, BaseList)
assert sub_list._instance is base_dict._instance
assert sub_list._name == "my_name.k"
assert base_dict._instance._changed_fields == []
# Challenge mark_as_changed from sublist
sub_list[1] = None
self.assertEqual(base_dict._instance._changed_fields, ["my_name.k.1"])
assert base_dict._instance._changed_fields == ["my_name.k.1"]
def test___getitem____subdict_gets_converted_to_BaseDict(self):
base_dict = self._get_basedict({"k": {"subk": "subv"}})
sub_dict = base_dict["k"]
self.assertEqual(sub_dict, {"subk": "subv"})
self.assertIsInstance(sub_dict, BaseDict)
self.assertIs(sub_dict._instance, base_dict._instance)
self.assertEqual(sub_dict._name, "my_name.k")
self.assertEqual(base_dict._instance._changed_fields, [])
assert sub_dict == {"subk": "subv"}
assert isinstance(sub_dict, BaseDict)
assert sub_dict._instance is base_dict._instance
assert sub_dict._name == "my_name.k"
assert base_dict._instance._changed_fields == []
# Challenge mark_as_changed from subdict
sub_dict["subk"] = None
self.assertEqual(base_dict._instance._changed_fields, ["my_name.k.subk"])
assert base_dict._instance._changed_fields == ["my_name.k.subk"]
def test_get_sublist_gets_converted_to_BaseList_just_like__getitem__(self):
base_dict = self._get_basedict({"k": [0, 1, 2]})
sub_list = base_dict.get("k")
self.assertEqual(sub_list, [0, 1, 2])
self.assertIsInstance(sub_list, BaseList)
assert sub_list == [0, 1, 2]
assert isinstance(sub_list, BaseList)
def test_get_returns_the_same_as___getitem__(self):
base_dict = self._get_basedict({"k": [0, 1, 2]})
get_ = base_dict.get("k")
getitem_ = base_dict["k"]
self.assertEqual(get_, getitem_)
assert get_ == getitem_
def test_get_default(self):
base_dict = self._get_basedict({})
sentinel = object()
self.assertEqual(base_dict.get("new"), None)
self.assertIs(base_dict.get("new", sentinel), sentinel)
assert base_dict.get("new") is None
assert base_dict.get("new", sentinel) is sentinel
def test___setitem___calls_mark_as_changed(self):
base_dict = self._get_basedict({})
base_dict["k"] = "v"
self.assertEqual(base_dict._instance._changed_fields, ["my_name.k"])
self.assertEqual(base_dict, {"k": "v"})
assert base_dict._instance._changed_fields == ["my_name.k"]
assert base_dict == {"k": "v"}
def test_update_calls_mark_as_changed(self):
base_dict = self._get_basedict({})
base_dict.update({"k": "v"})
self.assertEqual(base_dict._instance._changed_fields, ["my_name"])
assert base_dict._instance._changed_fields == ["my_name"]
def test___setattr____not_tracked_by_changes(self):
base_dict = self._get_basedict({})
base_dict.a_new_attr = "test"
self.assertEqual(base_dict._instance._changed_fields, [])
assert base_dict._instance._changed_fields == []
def test___delattr____tracked_by_changes(self):
# This is probably a bug as __setattr__ is not tracked
@ -146,18 +148,18 @@ class TestBaseDict(unittest.TestCase):
base_dict = self._get_basedict({})
base_dict.a_new_attr = "test"
del base_dict.a_new_attr
self.assertEqual(base_dict._instance._changed_fields, ["my_name.a_new_attr"])
assert base_dict._instance._changed_fields == ["my_name.a_new_attr"]
class TestBaseList(unittest.TestCase):
class TestBaseList:
@staticmethod
def _get_baselist(list_items):
"""Get a BaseList bound to a fake document instance"""
fake_doc = DocumentStub()
base_list = BaseList(list_items, instance=None, name="my_name")
base_list._instance = (
fake_doc
) # hack to inject the mock, it does not work in the constructor
fake_doc # hack to inject the mock, it does not work in the constructor
)
return base_list
def test___init___(self):
@ -167,14 +169,14 @@ class TestBaseList(unittest.TestCase):
list_items = [True]
doc = MyDoc()
base_list = BaseList(list_items, instance=doc, name="my_name")
self.assertIsInstance(base_list._instance, Document)
self.assertEqual(base_list._name, "my_name")
self.assertEqual(base_list, list_items)
assert isinstance(base_list._instance, Document)
assert base_list._name == "my_name"
assert base_list == list_items
def test___iter__(self):
values = [True, False, True, False]
base_list = BaseList(values, instance=None, name="my_name")
self.assertEqual(values, list(base_list))
assert values == list(base_list)
def test___iter___allow_modification_while_iterating_withou_error(self):
# regular list allows for this, thus this subclass must comply to that
@ -185,9 +187,9 @@ class TestBaseList(unittest.TestCase):
def test_append_calls_mark_as_changed(self):
base_list = self._get_baselist([])
self.assertFalse(base_list._instance._changed_fields)
assert not base_list._instance._changed_fields
base_list.append(True)
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test_subclass_append(self):
# Due to the way mark_as_changed_wrapper is implemented
@ -200,85 +202,85 @@ class TestBaseList(unittest.TestCase):
def test___getitem__using_simple_index(self):
base_list = self._get_baselist([0, 1, 2])
self.assertEqual(base_list[0], 0)
self.assertEqual(base_list[1], 1)
self.assertEqual(base_list[-1], 2)
assert base_list[0] == 0
assert base_list[1] == 1
assert base_list[-1] == 2
def test___getitem__using_slice(self):
base_list = self._get_baselist([0, 1, 2])
self.assertEqual(base_list[1:3], [1, 2])
self.assertEqual(base_list[0:3:2], [0, 2])
assert base_list[1:3] == [1, 2]
assert base_list[0:3:2] == [0, 2]
def test___getitem___using_slice_returns_list(self):
# Bug: using slice does not properly handles the instance
# and mark_as_changed behaviour.
base_list = self._get_baselist([0, 1, 2])
sliced = base_list[1:3]
self.assertEqual(sliced, [1, 2])
self.assertIsInstance(sliced, list)
self.assertEqual(base_list._instance._changed_fields, [])
assert sliced == [1, 2]
assert isinstance(sliced, list)
assert base_list._instance._changed_fields == []
def test___getitem__sublist_returns_BaseList_bound_to_instance(self):
base_list = self._get_baselist([[1, 2], [3, 4]])
sub_list = base_list[0]
self.assertEqual(sub_list, [1, 2])
self.assertIsInstance(sub_list, BaseList)
self.assertIs(sub_list._instance, base_list._instance)
self.assertEqual(sub_list._name, "my_name.0")
self.assertEqual(base_list._instance._changed_fields, [])
assert sub_list == [1, 2]
assert isinstance(sub_list, BaseList)
assert sub_list._instance is base_list._instance
assert sub_list._name == "my_name.0"
assert base_list._instance._changed_fields == []
# Challenge mark_as_changed from sublist
sub_list[1] = None
self.assertEqual(base_list._instance._changed_fields, ["my_name.0.1"])
assert base_list._instance._changed_fields == ["my_name.0.1"]
def test___getitem__subdict_returns_BaseList_bound_to_instance(self):
base_list = self._get_baselist([{"subk": "subv"}])
sub_dict = base_list[0]
self.assertEqual(sub_dict, {"subk": "subv"})
self.assertIsInstance(sub_dict, BaseDict)
self.assertIs(sub_dict._instance, base_list._instance)
self.assertEqual(sub_dict._name, "my_name.0")
self.assertEqual(base_list._instance._changed_fields, [])
assert sub_dict == {"subk": "subv"}
assert isinstance(sub_dict, BaseDict)
assert sub_dict._instance is base_list._instance
assert sub_dict._name == "my_name.0"
assert base_list._instance._changed_fields == []
# Challenge mark_as_changed from subdict
sub_dict["subk"] = None
self.assertEqual(base_list._instance._changed_fields, ["my_name.0.subk"])
assert base_list._instance._changed_fields == ["my_name.0.subk"]
def test_extend_calls_mark_as_changed(self):
base_list = self._get_baselist([])
base_list.extend([True])
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test_insert_calls_mark_as_changed(self):
base_list = self._get_baselist([])
base_list.insert(0, True)
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test_remove_calls_mark_as_changed(self):
base_list = self._get_baselist([True])
base_list.remove(True)
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test_remove_not_mark_as_changed_when_it_fails(self):
base_list = self._get_baselist([True])
with self.assertRaises(ValueError):
with pytest.raises(ValueError):
base_list.remove(False)
self.assertFalse(base_list._instance._changed_fields)
assert not base_list._instance._changed_fields
def test_pop_calls_mark_as_changed(self):
base_list = self._get_baselist([True])
base_list.pop()
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test_reverse_calls_mark_as_changed(self):
base_list = self._get_baselist([True, False])
base_list.reverse()
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test___delitem___calls_mark_as_changed(self):
base_list = self._get_baselist([True])
del base_list[0]
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test___setitem___calls_with_full_slice_mark_as_changed(self):
base_list = self._get_baselist([])
@ -286,8 +288,8 @@ class TestBaseList(unittest.TestCase):
0,
1,
] # Will use __setslice__ under py2 and __setitem__ under py3
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
self.assertEqual(base_list, [0, 1])
assert base_list._instance._changed_fields == ["my_name"]
assert base_list == [0, 1]
def test___setitem___calls_with_partial_slice_mark_as_changed(self):
base_list = self._get_baselist([0, 1, 2])
@ -295,103 +297,103 @@ class TestBaseList(unittest.TestCase):
1,
0,
] # Will use __setslice__ under py2 and __setitem__ under py3
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
self.assertEqual(base_list, [1, 0, 2])
assert base_list._instance._changed_fields == ["my_name"]
assert base_list == [1, 0, 2]
def test___setitem___calls_with_step_slice_mark_as_changed(self):
base_list = self._get_baselist([0, 1, 2])
base_list[0:3:2] = [-1, -2] # uses __setitem__ in both py2 & 3
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
self.assertEqual(base_list, [-1, 1, -2])
assert base_list._instance._changed_fields == ["my_name"]
assert base_list == [-1, 1, -2]
def test___setitem___with_slice(self):
base_list = self._get_baselist([0, 1, 2, 3, 4, 5])
base_list[0:6:2] = [None, None, None]
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
self.assertEqual(base_list, [None, 1, None, 3, None, 5])
assert base_list._instance._changed_fields == ["my_name"]
assert base_list == [None, 1, None, 3, None, 5]
def test___setitem___item_0_calls_mark_as_changed(self):
base_list = self._get_baselist([True])
base_list[0] = False
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
self.assertEqual(base_list, [False])
assert base_list._instance._changed_fields == ["my_name"]
assert base_list == [False]
def test___setitem___item_1_calls_mark_as_changed(self):
base_list = self._get_baselist([True, True])
base_list[1] = False
self.assertEqual(base_list._instance._changed_fields, ["my_name.1"])
self.assertEqual(base_list, [True, False])
assert base_list._instance._changed_fields == ["my_name.1"]
assert base_list == [True, False]
def test___delslice___calls_mark_as_changed(self):
base_list = self._get_baselist([0, 1])
del base_list[0:1]
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
self.assertEqual(base_list, [1])
assert base_list._instance._changed_fields == ["my_name"]
assert base_list == [1]
def test___iadd___calls_mark_as_changed(self):
base_list = self._get_baselist([True])
base_list += [False]
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test___imul___calls_mark_as_changed(self):
base_list = self._get_baselist([True])
self.assertEqual(base_list._instance._changed_fields, [])
assert base_list._instance._changed_fields == []
base_list *= 2
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test_sort_calls_not_marked_as_changed_when_it_fails(self):
base_list = self._get_baselist([True])
with self.assertRaises(TypeError):
with pytest.raises(TypeError):
base_list.sort(key=1)
self.assertEqual(base_list._instance._changed_fields, [])
assert base_list._instance._changed_fields == []
def test_sort_calls_mark_as_changed(self):
base_list = self._get_baselist([True, False])
base_list.sort()
self.assertEqual(base_list._instance._changed_fields, ["my_name"])
assert base_list._instance._changed_fields == ["my_name"]
def test_sort_calls_with_key(self):
base_list = self._get_baselist([1, 2, 11])
base_list.sort(key=lambda i: str(i))
self.assertEqual(base_list, [1, 11, 2])
assert base_list == [1, 11, 2]
class TestStrictDict(unittest.TestCase):
def strict_dict_class(self, *args, **kwargs):
return StrictDict.create(*args, **kwargs)
def setUp(self):
self.dtype = self.strict_dict_class(("a", "b", "c"))
def strict_dict_class(self, *args, **kwargs):
return StrictDict.create(*args, **kwargs)
def test_init(self):
d = self.dtype(a=1, b=1, c=1)
self.assertEqual((d.a, d.b, d.c), (1, 1, 1))
assert (d.a, d.b, d.c) == (1, 1, 1)
def test_iterkeys(self):
d = self.dtype(a=1)
self.assertEqual(list(iterkeys(d)), ["a"])
assert list(iterkeys(d)) == ["a"]
def test_len(self):
d = self.dtype(a=1)
self.assertEqual(len(d), 1)
assert len(d) == 1
def test_pop(self):
d = self.dtype(a=1)
self.assertIn("a", d)
assert "a" in d
d.pop("a")
self.assertNotIn("a", d)
assert "a" not in d
def test_repr(self):
d = self.dtype(a=1, b=2, c=3)
self.assertEqual(repr(d), '{"a": 1, "b": 2, "c": 3}')
assert repr(d) == '{"a": 1, "b": 2, "c": 3}'
# make sure quotes are escaped properly
d = self.dtype(a='"', b="'", c="")
self.assertEqual(repr(d), '{"a": \'"\', "b": "\'", "c": \'\'}')
assert repr(d) == '{"a": \'"\', "b": "\'", "c": \'\'}'
def test_init_fails_on_nonexisting_attrs(self):
with self.assertRaises(AttributeError):
with pytest.raises(AttributeError):
self.dtype(a=1, b=2, d=3)
def test_eq(self):
@ -403,45 +405,46 @@ class TestStrictDict(unittest.TestCase):
h = self.strict_dict_class(("a", "c", "b"))(a=1, b=1, c=1)
i = self.strict_dict_class(("a", "c", "b"))(a=1, b=1, c=2)
self.assertEqual(d, dd)
self.assertNotEqual(d, e)
self.assertNotEqual(d, f)
self.assertNotEqual(d, g)
self.assertNotEqual(f, d)
self.assertEqual(d, h)
self.assertNotEqual(d, i)
assert d == dd
assert d != e
assert d != f
assert d != g
assert f != d
assert d == h
assert d != i
def test_setattr_getattr(self):
d = self.dtype()
d.a = 1
self.assertEqual(d.a, 1)
self.assertRaises(AttributeError, getattr, d, "b")
assert d.a == 1
with pytest.raises(AttributeError):
getattr(d, "b")
def test_setattr_raises_on_nonexisting_attr(self):
d = self.dtype()
with self.assertRaises(AttributeError):
with pytest.raises(AttributeError):
d.x = 1
def test_setattr_getattr_special(self):
d = self.strict_dict_class(["items"])
d.items = 1
self.assertEqual(d.items, 1)
assert d.items == 1
def test_get(self):
d = self.dtype(a=1)
self.assertEqual(d.get("a"), 1)
self.assertEqual(d.get("b", "bla"), "bla")
assert d.get("a") == 1
assert d.get("b", "bla") == "bla"
def test_items(self):
d = self.dtype(a=1)
self.assertEqual(d.items(), [("a", 1)])
assert d.items() == [("a", 1)]
d = self.dtype(a=1, b=2)
self.assertEqual(d.items(), [("a", 1), ("b", 2)])
assert d.items() == [("a", 1), ("b", 2)]
def test_mappings_protocol(self):
d = self.dtype(a=1, b=2)
self.assertEqual(dict(d), {"a": 1, "b": 2})
self.assertEqual(dict(**d), {"a": 1, "b": 2})
assert dict(d) == {"a": 1, "b": 2}
assert dict(**d) == {"a": 1, "b": 2}
if __name__ == "__main__":

View File

@ -42,37 +42,37 @@ class FieldTest(unittest.TestCase):
group.save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
len(group_obj._data["members"])
self.assertEqual(q, 1)
assert q == 1
len(group_obj.members)
self.assertEqual(q, 2)
assert q == 2
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
# Document select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first().select_related()
self.assertEqual(q, 2)
assert q == 2
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
# Queryset select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_objs = Group.objects.select_related()
self.assertEqual(q, 2)
assert q == 2
for group_obj in group_objs:
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
User.drop_collection()
Group.drop_collection()
@ -99,40 +99,40 @@ class FieldTest(unittest.TestCase):
group.reload() # Confirm reload works
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 2)
self.assertTrue(group_obj._data["members"]._dereferenced)
assert q == 2
assert group_obj._data["members"]._dereferenced
# verifies that no additional queries gets executed
# if we re-iterate over the ListField once it is
# dereferenced
[m for m in group_obj.members]
self.assertEqual(q, 2)
self.assertTrue(group_obj._data["members"]._dereferenced)
assert q == 2
assert group_obj._data["members"]._dereferenced
# Document select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first().select_related()
self.assertEqual(q, 2)
assert q == 2
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
# Queryset select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_objs = Group.objects.select_related()
self.assertEqual(q, 2)
assert q == 2
for group_obj in group_objs:
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
def test_list_item_dereference_orphan_dbref(self):
"""Ensure that orphan DBRef items in ListFields are dereferenced.
@ -159,21 +159,21 @@ class FieldTest(unittest.TestCase):
# Group.members list is an orphan DBRef
User.objects[0].delete()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 2)
self.assertTrue(group_obj._data["members"]._dereferenced)
assert q == 2
assert group_obj._data["members"]._dereferenced
# verifies that no additional queries gets executed
# if we re-iterate over the ListField once it is
# dereferenced
[m for m in group_obj.members]
self.assertEqual(q, 2)
self.assertTrue(group_obj._data["members"]._dereferenced)
assert q == 2
assert group_obj._data["members"]._dereferenced
User.drop_collection()
Group.drop_collection()
@ -197,8 +197,8 @@ class FieldTest(unittest.TestCase):
Group(members=User.objects).save()
group = Group.objects.first()
self.assertEqual(Group._get_collection().find_one()["members"], [1])
self.assertEqual(group.members, [user])
assert Group._get_collection().find_one()["members"] == [1]
assert group.members == [user]
def test_handle_old_style_references(self):
"""Ensure that DBRef items in ListFields are dereferenced.
@ -231,8 +231,8 @@ class FieldTest(unittest.TestCase):
group.save()
group = Group.objects.first()
self.assertEqual(group.members[0].name, "user 1")
self.assertEqual(group.members[-1].name, "String!")
assert group.members[0].name == "user 1"
assert group.members[-1].name == "String!"
def test_migrate_references(self):
"""Example of migrating ReferenceField storage
@ -253,12 +253,12 @@ class FieldTest(unittest.TestCase):
group = Group(author=user, members=[user]).save()
raw_data = Group._get_collection().find_one()
self.assertIsInstance(raw_data["author"], DBRef)
self.assertIsInstance(raw_data["members"][0], DBRef)
assert isinstance(raw_data["author"], DBRef)
assert isinstance(raw_data["members"][0], DBRef)
group = Group.objects.first()
self.assertEqual(group.author, user)
self.assertEqual(group.members, [user])
assert group.author == user
assert group.members == [user]
# Migrate the model definition
class Group(Document):
@ -273,12 +273,12 @@ class FieldTest(unittest.TestCase):
g.save()
group = Group.objects.first()
self.assertEqual(group.author, user)
self.assertEqual(group.members, [user])
assert group.author == user
assert group.members == [user]
raw_data = Group._get_collection().find_one()
self.assertIsInstance(raw_data["author"], ObjectId)
self.assertIsInstance(raw_data["members"][0], ObjectId)
assert isinstance(raw_data["author"], ObjectId)
assert isinstance(raw_data["members"][0], ObjectId)
def test_recursive_reference(self):
"""Ensure that ReferenceFields can reference their own documents.
@ -309,43 +309,43 @@ class FieldTest(unittest.TestCase):
Employee(name="Funky Gibbon", boss=bill, friends=friends).save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
peter = Employee.objects.with_id(peter.id)
self.assertEqual(q, 1)
assert q == 1
peter.boss
self.assertEqual(q, 2)
assert q == 2
peter.friends
self.assertEqual(q, 3)
assert q == 3
# Document select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
peter = Employee.objects.with_id(peter.id).select_related()
self.assertEqual(q, 2)
assert q == 2
self.assertEqual(peter.boss, bill)
self.assertEqual(q, 2)
assert peter.boss == bill
assert q == 2
self.assertEqual(peter.friends, friends)
self.assertEqual(q, 2)
assert peter.friends == friends
assert q == 2
# Queryset select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
employees = Employee.objects(boss=bill).select_related()
self.assertEqual(q, 2)
assert q == 2
for employee in employees:
self.assertEqual(employee.boss, bill)
self.assertEqual(q, 2)
assert employee.boss == bill
assert q == 2
self.assertEqual(employee.friends, friends)
self.assertEqual(q, 2)
assert employee.friends == friends
assert q == 2
def test_list_of_lists_of_references(self):
class User(Document):
@ -366,10 +366,10 @@ class FieldTest(unittest.TestCase):
u3 = User.objects.create(name="u3")
SimpleList.objects.create(users=[u1, u2, u3])
self.assertEqual(SimpleList.objects.all()[0].users, [u1, u2, u3])
assert SimpleList.objects.all()[0].users == [u1, u2, u3]
Post.objects.create(user_lists=[[u1, u2], [u3]])
self.assertEqual(Post.objects.all()[0].user_lists, [[u1, u2], [u3]])
assert Post.objects.all()[0].user_lists == [[u1, u2], [u3]]
def test_circular_reference(self):
"""Ensure you can handle circular references
@ -403,9 +403,7 @@ class FieldTest(unittest.TestCase):
daughter.relations.append(self_rel)
daughter.save()
self.assertEqual(
"[<Person: Mother>, <Person: Daughter>]", "%s" % Person.objects()
)
assert "[<Person: Mother>, <Person: Daughter>]" == "%s" % Person.objects()
def test_circular_reference_on_self(self):
"""Ensure you can handle circular references
@ -432,9 +430,7 @@ class FieldTest(unittest.TestCase):
daughter.relations.append(daughter)
daughter.save()
self.assertEqual(
"[<Person: Mother>, <Person: Daughter>]", "%s" % Person.objects()
)
assert "[<Person: Mother>, <Person: Daughter>]" == "%s" % Person.objects()
def test_circular_tree_reference(self):
"""Ensure you can handle circular references with more than one level
@ -473,9 +469,9 @@ class FieldTest(unittest.TestCase):
anna.other.name = "Anna's friends"
anna.save()
self.assertEqual(
"[<Person: Paul>, <Person: Maria>, <Person: Julia>, <Person: Anna>]",
"%s" % Person.objects(),
assert (
"[<Person: Paul>, <Person: Maria>, <Person: Julia>, <Person: Anna>]"
== "%s" % Person.objects()
)
def test_generic_reference(self):
@ -516,52 +512,52 @@ class FieldTest(unittest.TestCase):
group.save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for m in group_obj.members:
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
# Document select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first().select_related()
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for m in group_obj.members:
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
# Queryset select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_objs = Group.objects.select_related()
self.assertEqual(q, 4)
assert q == 4
for group_obj in group_objs:
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for m in group_obj.members:
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
def test_generic_reference_orphan_dbref(self):
"""Ensure that generic orphan DBRef items in ListFields are dereferenced.
@ -604,18 +600,18 @@ class FieldTest(unittest.TestCase):
# an orphan DBRef in the GenericReference ListField
UserA.objects[0].delete()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 4)
self.assertTrue(group_obj._data["members"]._dereferenced)
assert q == 4
assert group_obj._data["members"]._dereferenced
[m for m in group_obj.members]
self.assertEqual(q, 4)
self.assertTrue(group_obj._data["members"]._dereferenced)
assert q == 4
assert group_obj._data["members"]._dereferenced
UserA.drop_collection()
UserB.drop_collection()
@ -660,52 +656,52 @@ class FieldTest(unittest.TestCase):
group.save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for m in group_obj.members:
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
# Document select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first().select_related()
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for m in group_obj.members:
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
# Queryset select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_objs = Group.objects.select_related()
self.assertEqual(q, 4)
assert q == 4
for group_obj in group_objs:
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for m in group_obj.members:
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
UserA.drop_collection()
UserB.drop_collection()
@ -735,43 +731,43 @@ class FieldTest(unittest.TestCase):
group.save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
for k, m in iteritems(group_obj.members):
self.assertIsInstance(m, User)
assert isinstance(m, User)
# Document select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first().select_related()
self.assertEqual(q, 2)
assert q == 2
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
for k, m in iteritems(group_obj.members):
self.assertIsInstance(m, User)
assert isinstance(m, User)
# Queryset select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_objs = Group.objects.select_related()
self.assertEqual(q, 2)
assert q == 2
for group_obj in group_objs:
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
for k, m in iteritems(group_obj.members):
self.assertIsInstance(m, User)
assert isinstance(m, User)
User.drop_collection()
Group.drop_collection()
@ -813,65 +809,65 @@ class FieldTest(unittest.TestCase):
group.save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for k, m in iteritems(group_obj.members):
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
# Document select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first().select_related()
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for k, m in iteritems(group_obj.members):
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
# Queryset select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_objs = Group.objects.select_related()
self.assertEqual(q, 4)
assert q == 4
for group_obj in group_objs:
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for k, m in iteritems(group_obj.members):
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
Group.objects.delete()
Group().save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 1)
self.assertEqual(group_obj.members, {})
assert q == 1
assert group_obj.members == {}
UserA.drop_collection()
UserB.drop_collection()
@ -903,52 +899,52 @@ class FieldTest(unittest.TestCase):
group.save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
for k, m in iteritems(group_obj.members):
self.assertIsInstance(m, UserA)
assert isinstance(m, UserA)
# Document select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first().select_related()
self.assertEqual(q, 2)
assert q == 2
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
for k, m in iteritems(group_obj.members):
self.assertIsInstance(m, UserA)
assert isinstance(m, UserA)
# Queryset select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_objs = Group.objects.select_related()
self.assertEqual(q, 2)
assert q == 2
for group_obj in group_objs:
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
[m for m in group_obj.members]
self.assertEqual(q, 2)
assert q == 2
for k, m in iteritems(group_obj.members):
self.assertIsInstance(m, UserA)
assert isinstance(m, UserA)
UserA.drop_collection()
Group.drop_collection()
@ -990,64 +986,64 @@ class FieldTest(unittest.TestCase):
group.save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for k, m in iteritems(group_obj.members):
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
# Document select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first().select_related()
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for k, m in iteritems(group_obj.members):
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
# Queryset select_related
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_objs = Group.objects.select_related()
self.assertEqual(q, 4)
assert q == 4
for group_obj in group_objs:
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
[m for m in group_obj.members]
self.assertEqual(q, 4)
assert q == 4
for k, m in iteritems(group_obj.members):
self.assertIn("User", m.__class__.__name__)
assert "User" in m.__class__.__name__
Group.objects.delete()
Group().save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
[m for m in group_obj.members]
self.assertEqual(q, 1)
assert q == 1
UserA.drop_collection()
UserB.drop_collection()
@ -1075,8 +1071,8 @@ class FieldTest(unittest.TestCase):
root.save()
root = root.reload()
self.assertEqual(root.children, [company])
self.assertEqual(company.parents, [root])
assert root.children == [company]
assert company.parents == [root]
def test_dict_in_dbref_instance(self):
class Person(Document):
@ -1102,8 +1098,8 @@ class FieldTest(unittest.TestCase):
room_101.save()
room = Room.objects.first().select_related()
self.assertEqual(room.staffs_with_position[0]["staff"], sarah)
self.assertEqual(room.staffs_with_position[1]["staff"], bob)
assert room.staffs_with_position[0]["staff"] == sarah
assert room.staffs_with_position[1]["staff"] == bob
def test_document_reload_no_inheritance(self):
class Foo(Document):
@ -1133,8 +1129,8 @@ class FieldTest(unittest.TestCase):
foo.save()
foo.reload()
self.assertEqual(type(foo.bar), Bar)
self.assertEqual(type(foo.baz), Baz)
assert type(foo.bar) == Bar
assert type(foo.baz) == Baz
def test_document_reload_reference_integrity(self):
"""
@ -1166,13 +1162,13 @@ class FieldTest(unittest.TestCase):
concurrent_change_user = User.objects.get(id=1)
concurrent_change_user.name = "new-name"
concurrent_change_user.save()
self.assertNotEqual(user.name, "new-name")
assert user.name != "new-name"
msg = Message.objects.get(id=1)
msg.reload()
self.assertEqual(msg.topic, topic)
self.assertEqual(msg.author, user)
self.assertEqual(msg.author.name, "new-name")
assert msg.topic == topic
assert msg.author == user
assert msg.author.name == "new-name"
def test_list_lookup_not_checked_in_map(self):
"""Ensure we dereference list data correctly
@ -1194,8 +1190,8 @@ class FieldTest(unittest.TestCase):
Message(id=1, comments=[c1, c2]).save()
msg = Message.objects.get(id=1)
self.assertEqual(0, msg.comments[0].id)
self.assertEqual(1, msg.comments[1].id)
assert 0 == msg.comments[0].id
assert 1 == msg.comments[1].id
def test_list_item_dereference_dref_false_save_doesnt_cause_extra_queries(self):
"""Ensure that DBRef items in ListFields are dereferenced.
@ -1217,15 +1213,15 @@ class FieldTest(unittest.TestCase):
Group(name="Test", members=User.objects).save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
group_obj.name = "new test"
group_obj.save()
self.assertEqual(q, 2)
assert q == 2
def test_list_item_dereference_dref_true_save_doesnt_cause_extra_queries(self):
"""Ensure that DBRef items in ListFields are dereferenced.
@ -1247,15 +1243,15 @@ class FieldTest(unittest.TestCase):
Group(name="Test", members=User.objects).save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
group_obj.name = "new test"
group_obj.save()
self.assertEqual(q, 2)
assert q == 2
def test_generic_reference_save_doesnt_cause_extra_queries(self):
class UserA(Document):
@ -1287,15 +1283,15 @@ class FieldTest(unittest.TestCase):
Group(name="test", members=members).save()
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
group_obj = Group.objects.first()
self.assertEqual(q, 1)
assert q == 1
group_obj.name = "new test"
group_obj.save()
self.assertEqual(q, 2)
assert q == 2
def test_objectid_reference_across_databases(self):
# mongoenginetest - Is default connection alias from setUp()
@ -1319,10 +1315,10 @@ class FieldTest(unittest.TestCase):
# Can't use query_counter across databases - so test the _data object
book = Book.objects.first()
self.assertNotIsInstance(book._data["author"], User)
assert not isinstance(book._data["author"], User)
book.select_related()
self.assertIsInstance(book._data["author"], User)
assert isinstance(book._data["author"], User)
def test_non_ascii_pk(self):
"""
@ -1346,7 +1342,7 @@ class FieldTest(unittest.TestCase):
BrandGroup(title="top_brands", brands=[brand1, brand2]).save()
brand_groups = BrandGroup.objects().all()
self.assertEqual(2, len([brand for bg in brand_groups for brand in bg.brands]))
assert 2 == len([brand for bg in brand_groups for brand in bg.brands])
def test_dereferencing_embedded_listfield_referencefield(self):
class Tag(Document):
@ -1370,7 +1366,7 @@ class FieldTest(unittest.TestCase):
Page(tags=[tag], posts=[post]).save()
page = Page.objects.first()
self.assertEqual(page.tags[0], page.posts[0].tags[0])
assert page.tags[0] == page.posts[0].tags[0]
def test_select_related_follows_embedded_referencefields(self):
class Song(Document):
@ -1390,12 +1386,12 @@ class FieldTest(unittest.TestCase):
playlist = Playlist.objects.create(items=items)
with query_counter() as q:
self.assertEqual(q, 0)
assert q == 0
playlist = Playlist.objects.first().select_related()
songs = [item.song for item in playlist.items]
self.assertEqual(q, 2)
assert q == 2
if __name__ == "__main__":

View File

@ -1,7 +1,6 @@
import unittest
from pymongo import ReadPreference
from pymongo import MongoClient
from pymongo import MongoClient, ReadPreference
import mongoengine
from mongoengine.connection import ConnectionFailure
@ -25,21 +24,20 @@ class ConnectionTest(unittest.TestCase):
def test_replicaset_uri_passes_read_preference(self):
"""Requires a replica set called "rs" on port 27017
"""
try:
conn = mongoengine.connect(
db="mongoenginetest",
host="mongodb://localhost/mongoenginetest?replicaSet=rs",
read_preference=READ_PREF,
)
except ConnectionFailure as e:
except ConnectionFailure:
return
if not isinstance(conn, CONN_CLASS):
# really???
return
self.assertEqual(conn.read_preference, READ_PREF)
assert conn.read_preference == READ_PREF
if __name__ == "__main__":

View File

@ -7,7 +7,7 @@ from mongoengine import signals
signal_output = []
class SignalTests(unittest.TestCase):
class TestSignal(unittest.TestCase):
"""
Testing signals before/after saving and deleting.
"""
@ -245,7 +245,7 @@ class SignalTests(unittest.TestCase):
# Note that there is a chance that the following assert fails in case
# some receivers (eventually created in other tests)
# gets garbage collected (https://pythonhosted.org/blinker/#blinker.base.Signal.connect)
self.assertEqual(self.pre_signals, post_signals)
assert self.pre_signals == post_signals
def test_model_signals(self):
""" Model saves should throw some signals. """
@ -267,97 +267,76 @@ class SignalTests(unittest.TestCase):
self.get_signal_output(lambda: None) # eliminate signal output
a1 = self.Author.objects(name="Bill Shakespeare")[0]
self.assertEqual(
self.get_signal_output(create_author),
[
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
],
)
assert self.get_signal_output(create_author) == [
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
]
a1 = self.Author(name="Bill Shakespeare")
self.assertEqual(
self.get_signal_output(a1.save),
[
"pre_save signal, Bill Shakespeare",
{},
"pre_save_post_validation signal, Bill Shakespeare",
"Is created",
{},
"post_save signal, Bill Shakespeare",
"post_save dirty keys, ['name']",
"Is created",
{},
],
)
assert self.get_signal_output(a1.save) == [
"pre_save signal, Bill Shakespeare",
{},
"pre_save_post_validation signal, Bill Shakespeare",
"Is created",
{},
"post_save signal, Bill Shakespeare",
"post_save dirty keys, ['name']",
"Is created",
{},
]
a1.reload()
a1.name = "William Shakespeare"
self.assertEqual(
self.get_signal_output(a1.save),
[
"pre_save signal, William Shakespeare",
{},
"pre_save_post_validation signal, William Shakespeare",
"Is updated",
{},
"post_save signal, William Shakespeare",
"post_save dirty keys, ['name']",
"Is updated",
{},
],
)
assert self.get_signal_output(a1.save) == [
"pre_save signal, William Shakespeare",
{},
"pre_save_post_validation signal, William Shakespeare",
"Is updated",
{},
"post_save signal, William Shakespeare",
"post_save dirty keys, ['name']",
"Is updated",
{},
]
self.assertEqual(
self.get_signal_output(a1.delete),
[
"pre_delete signal, William Shakespeare",
{},
"post_delete signal, William Shakespeare",
{},
],
)
assert self.get_signal_output(a1.delete) == [
"pre_delete signal, William Shakespeare",
{},
"post_delete signal, William Shakespeare",
{},
]
self.assertEqual(
self.get_signal_output(load_existing_author),
[
"pre_init signal, Author",
{"id": 2, "name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = False",
],
)
assert self.get_signal_output(load_existing_author) == [
"pre_init signal, Author",
{"id": 2, "name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = False",
]
self.assertEqual(
self.get_signal_output(bulk_create_author_with_load),
[
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
"pre_bulk_insert signal, [<Author: Bill Shakespeare>]",
{},
"pre_init signal, Author",
{"id": 3, "name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = False",
"post_bulk_insert signal, [<Author: Bill Shakespeare>]",
"Is loaded",
{},
],
)
assert self.get_signal_output(bulk_create_author_with_load) == [
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
"pre_bulk_insert signal, [<Author: Bill Shakespeare>]",
{},
"pre_init signal, Author",
{"id": 3, "name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = False",
"post_bulk_insert signal, [<Author: Bill Shakespeare>]",
"Is loaded",
{},
]
self.assertEqual(
self.get_signal_output(bulk_create_author_without_load),
[
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
"pre_bulk_insert signal, [<Author: Bill Shakespeare>]",
{},
"post_bulk_insert signal, [<Author: Bill Shakespeare>]",
"Not loaded",
{},
],
)
assert self.get_signal_output(bulk_create_author_without_load) == [
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
"pre_bulk_insert signal, [<Author: Bill Shakespeare>]",
{},
"post_bulk_insert signal, [<Author: Bill Shakespeare>]",
"Not loaded",
{},
]
def test_signal_kwargs(self):
""" Make sure signal_kwargs is passed to signals calls. """
@ -367,83 +346,74 @@ class SignalTests(unittest.TestCase):
a.save(signal_kwargs={"live": True, "die": False})
a.delete(signal_kwargs={"live": False, "die": True})
self.assertEqual(
self.get_signal_output(live_and_let_die),
[
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
"pre_save signal, Bill Shakespeare",
{"die": False, "live": True},
"pre_save_post_validation signal, Bill Shakespeare",
"Is created",
{"die": False, "live": True},
"post_save signal, Bill Shakespeare",
"post_save dirty keys, ['name']",
"Is created",
{"die": False, "live": True},
"pre_delete signal, Bill Shakespeare",
{"die": True, "live": False},
"post_delete signal, Bill Shakespeare",
{"die": True, "live": False},
],
)
assert self.get_signal_output(live_and_let_die) == [
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
"pre_save signal, Bill Shakespeare",
{"die": False, "live": True},
"pre_save_post_validation signal, Bill Shakespeare",
"Is created",
{"die": False, "live": True},
"post_save signal, Bill Shakespeare",
"post_save dirty keys, ['name']",
"Is created",
{"die": False, "live": True},
"pre_delete signal, Bill Shakespeare",
{"die": True, "live": False},
"post_delete signal, Bill Shakespeare",
{"die": True, "live": False},
]
def bulk_create_author():
a1 = self.Author(name="Bill Shakespeare")
self.Author.objects.insert([a1], signal_kwargs={"key": True})
self.assertEqual(
self.get_signal_output(bulk_create_author),
[
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
"pre_bulk_insert signal, [<Author: Bill Shakespeare>]",
{"key": True},
"pre_init signal, Author",
{"id": 2, "name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = False",
"post_bulk_insert signal, [<Author: Bill Shakespeare>]",
"Is loaded",
{"key": True},
],
)
assert self.get_signal_output(bulk_create_author) == [
"pre_init signal, Author",
{"name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = True",
"pre_bulk_insert signal, [<Author: Bill Shakespeare>]",
{"key": True},
"pre_init signal, Author",
{"id": 2, "name": "Bill Shakespeare"},
"post_init signal, Bill Shakespeare, document._created = False",
"post_bulk_insert signal, [<Author: Bill Shakespeare>]",
"Is loaded",
{"key": True},
]
def test_queryset_delete_signals(self):
""" Queryset delete should throw some signals. """
self.Another(name="Bill Shakespeare").save()
self.assertEqual(
self.get_signal_output(self.Another.objects.delete),
[
"pre_delete signal, Bill Shakespeare",
{},
"post_delete signal, Bill Shakespeare",
{},
],
)
assert self.get_signal_output(self.Another.objects.delete) == [
"pre_delete signal, Bill Shakespeare",
{},
"post_delete signal, Bill Shakespeare",
{},
]
def test_signals_with_explicit_doc_ids(self):
""" Model saves must have a created flag the first time."""
ei = self.ExplicitId(id=123)
# post save must received the created flag, even if there's already
# an object id present
self.assertEqual(self.get_signal_output(ei.save), ["Is created"])
assert self.get_signal_output(ei.save) == ["Is created"]
# second time, it must be an update
self.assertEqual(self.get_signal_output(ei.save), ["Is updated"])
assert self.get_signal_output(ei.save) == ["Is updated"]
def test_signals_with_switch_collection(self):
ei = self.ExplicitId(id=123)
ei.switch_collection("explicit__1")
self.assertEqual(self.get_signal_output(ei.save), ["Is created"])
assert self.get_signal_output(ei.save) == ["Is created"]
ei.switch_collection("explicit__1")
self.assertEqual(self.get_signal_output(ei.save), ["Is updated"])
assert self.get_signal_output(ei.save) == ["Is updated"]
ei.switch_collection("explicit__1", keep_created=False)
self.assertEqual(self.get_signal_output(ei.save), ["Is created"])
assert self.get_signal_output(ei.save) == ["Is created"]
ei.switch_collection("explicit__1", keep_created=False)
self.assertEqual(self.get_signal_output(ei.save), ["Is created"])
assert self.get_signal_output(ei.save) == ["Is created"]
def test_signals_with_switch_db(self):
connect("mongoenginetest")
@ -451,14 +421,14 @@ class SignalTests(unittest.TestCase):
ei = self.ExplicitId(id=123)
ei.switch_db("testdb-1")
self.assertEqual(self.get_signal_output(ei.save), ["Is created"])
assert self.get_signal_output(ei.save) == ["Is created"]
ei.switch_db("testdb-1")
self.assertEqual(self.get_signal_output(ei.save), ["Is updated"])
assert self.get_signal_output(ei.save) == ["Is updated"]
ei.switch_db("testdb-1", keep_created=False)
self.assertEqual(self.get_signal_output(ei.save), ["Is created"])
assert self.get_signal_output(ei.save) == ["Is created"]
ei.switch_db("testdb-1", keep_created=False)
self.assertEqual(self.get_signal_output(ei.save), ["Is created"])
assert self.get_signal_output(ei.save) == ["Is created"]
def test_signals_bulk_insert(self):
def bulk_set_active_post():
@ -470,16 +440,13 @@ class SignalTests(unittest.TestCase):
self.Post.objects.insert(posts)
results = self.get_signal_output(bulk_set_active_post)
self.assertEqual(
results,
[
"pre_bulk_insert signal, [(<Post: Post 1>, {'active': False}), (<Post: Post 2>, {'active': False}), (<Post: Post 3>, {'active': False})]",
{},
"post_bulk_insert signal, [(<Post: Post 1>, {'active': True}), (<Post: Post 2>, {'active': True}), (<Post: Post 3>, {'active': True})]",
"Is loaded",
{},
],
)
assert results == [
"pre_bulk_insert signal, [(<Post: Post 1>, {'active': False}), (<Post: Post 2>, {'active': False}), (<Post: Post 3>, {'active': False})]",
{},
"post_bulk_insert signal, [(<Post: Post 1>, {'active': True}), (<Post: Post 2>, {'active': True}), (<Post: Post 3>, {'active': True})]",
"Is loaded",
{},
]
if __name__ == "__main__":

View File

@ -1,32 +1,34 @@
import unittest
import re
import unittest
import pytest
from mongoengine.base.utils import LazyRegexCompiler
signal_output = []
class LazyRegexCompilerTest(unittest.TestCase):
class TestLazyRegexCompiler:
def test_lazy_regex_compiler_verify_laziness_of_descriptor(self):
class UserEmail(object):
EMAIL_REGEX = LazyRegexCompiler("@", flags=32)
descriptor = UserEmail.__dict__["EMAIL_REGEX"]
self.assertIsNone(descriptor._compiled_regex)
assert descriptor._compiled_regex is None
regex = UserEmail.EMAIL_REGEX
self.assertEqual(regex, re.compile("@", flags=32))
self.assertEqual(regex.search("user@domain.com").group(), "@")
assert regex == re.compile("@", flags=32)
assert regex.search("user@domain.com").group() == "@"
user_email = UserEmail()
self.assertIs(user_email.EMAIL_REGEX, UserEmail.EMAIL_REGEX)
assert user_email.EMAIL_REGEX is UserEmail.EMAIL_REGEX
def test_lazy_regex_compiler_verify_cannot_set_descriptor_on_instance(self):
class UserEmail(object):
EMAIL_REGEX = LazyRegexCompiler("@")
user_email = UserEmail()
with self.assertRaises(AttributeError):
with pytest.raises(AttributeError):
user_email.EMAIL_REGEX = re.compile("@")
def test_lazy_regex_compiler_verify_can_override_class_attr(self):
@ -34,6 +36,4 @@ class LazyRegexCompilerTest(unittest.TestCase):
EMAIL_REGEX = LazyRegexCompiler("@")
UserEmail.EMAIL_REGEX = re.compile("cookies")
self.assertEqual(
UserEmail.EMAIL_REGEX.search("Cake & cookies").group(), "cookies"
)
assert UserEmail.EMAIL_REGEX.search("Cake & cookies").group() == "cookies"

View File

@ -1,10 +1,9 @@
import operator
import unittest
from nose.plugins.skip import SkipTest
import pytest
from mongoengine import connect
from mongoengine.connection import get_db, disconnect_all
from mongoengine.connection import disconnect_all, get_db
from mongoengine.mongodb_support import get_mongodb_version
@ -37,7 +36,7 @@ def get_as_pymongo(doc):
def _decorated_with_ver_requirement(func, mongo_version_req, oper):
"""Return a MongoDB version requirement decorator.
The resulting decorator will raise a SkipTest exception if the current
The resulting decorator will skip the test if the current
MongoDB version doesn't match the provided version/operator.
For example, if you define a decorator like so:
@ -59,9 +58,8 @@ def _decorated_with_ver_requirement(func, mongo_version_req, oper):
if oper(mongodb_v, mongo_version_req):
return func(*args, **kwargs)
raise SkipTest(
"Needs MongoDB v{}+".format(".".join(str(n) for n in mongo_version_req))
)
pretty_version = ".".join(str(n) for n in mongo_version_req)
pytest.skip("Needs MongoDB v{}+".format(pretty_version))
_inner.__name__ = func.__name__
_inner.__doc__ = func.__doc__

View File

@ -3,11 +3,11 @@ envlist = {py27,py35,pypy,pypy3}-{mg34,mg36, mg39}
[testenv]
commands =
python setup.py nosetests {posargs}
python setup.py test {posargs}
deps =
nose
mg34: pymongo>=3.4,<3.5
mg36: pymongo>=3.6,<3.7
mg39: pymongo>=3.9,<4.0
mg39: pymongo>=3.9,<3.10
mg310: pymongo>=3.10,<3.11
setenv =
PYTHON_EGG_CACHE = {envdir}/python-eggs