Skip to content

Commit 6133f04

Browse files
committed
Manual merge conflicts in AUTHORS
2 parents 3c18f79 + a6e996d commit 6133f04

File tree

14 files changed

+268
-41
lines changed

14 files changed

+268
-41
lines changed

.travis.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ python:
55
- '3.2'
66
- '3.3'
77
- '3.4'
8+
- '3.5'
89
- pypy
910
- pypy3
1011
env:

AUTHORS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,4 +229,7 @@ that much better:
229229
* Emile Caron (https://github.com/emilecaron)
230230
* Amit Lichtenberg (https://github.com/amitlicht)
231231
* Lars Butler (https://github.com/larsbutler)
232+
* George Macon (https://github.com/gmacon)
233+
* Ashley Whetter (https://github.com/AWhetter)
232234
* Paul-Armand Verhaegen (https://github.com/paularmand)
235+

docs/changelog.rst

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,21 @@
22
Changelog
33
=========
44

5-
Changes in 0.10.1 - DEV
5+
Changes in 0.10.4 - DEV
6+
=======================
7+
- SaveConditionError is now importable from the top level package. #1165
8+
9+
Changes in 0.10.3
10+
=================
11+
- Fix `read_preference` (it had chaining issues with PyMongo 2.x and it didn't work at all with PyMongo 3.x) #1042
12+
13+
Changes in 0.10.2
14+
=================
15+
- Allow shard key to point to a field in an embedded document. #551
16+
- Allow arbirary metadata in fields. #1129
17+
- ReferenceFields now support abstract document types. #837
18+
19+
Changes in 0.10.1
620
=======================
721
- Fix infinite recursion with CASCADE delete rules under specific conditions. #1046
822
- Fix CachedReferenceField bug when loading cached docs as DBRef but failing to save them. #1047

docs/guide/defining-documents.rst

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -172,11 +172,11 @@ arguments can be set on all fields:
172172
class Shirt(Document):
173173
size = StringField(max_length=3, choices=SIZE)
174174

175-
:attr:`help_text` (Default: None)
176-
Optional help text to output with the field -- used by form libraries
177-
178-
:attr:`verbose_name` (Default: None)
179-
Optional human-readable name for the field -- used by form libraries
175+
:attr:`**kwargs` (Optional)
176+
You can supply additional metadata as arbitrary additional keyword
177+
arguments. You can not override existing attributes, however. Common
178+
choices include `help_text` and `verbose_name`, commonly used by form and
179+
widget libraries.
180180

181181

182182
List fields

mongoengine/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
__all__ = (list(document.__all__) + fields.__all__ + connection.__all__ +
1515
list(queryset.__all__) + signals.__all__ + list(errors.__all__))
1616

17-
VERSION = (0, 10, 0)
17+
VERSION = (0, 10, 1)
1818

1919

2020
def get_version():

mongoengine/base/fields.py

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ class BaseField(object):
4141

4242
def __init__(self, db_field=None, name=None, required=False, default=None,
4343
unique=False, unique_with=None, primary_key=False,
44-
validation=None, choices=None, verbose_name=None,
45-
help_text=None, null=False, sparse=False, custom_data=None):
44+
validation=None, choices=None, null=False, sparse=False,
45+
**kwargs):
4646
"""
4747
:param db_field: The database field to store this field in
4848
(defaults to the name of the field)
@@ -60,16 +60,15 @@ def __init__(self, db_field=None, name=None, required=False, default=None,
6060
field. Generally this is deprecated in favour of the
6161
`FIELD.validate` method
6262
:param choices: (optional) The valid choices
63-
:param verbose_name: (optional) The verbose name for the field.
64-
Designed to be human readable and is often used when generating
65-
model forms from the document model.
66-
:param help_text: (optional) The help text for this field and is often
67-
used when generating model forms from the document model.
6863
:param null: (optional) Is the field value can be null. If no and there is a default value
6964
then the default value is set
7065
:param sparse: (optional) `sparse=True` combined with `unique=True` and `required=False`
7166
means that uniqueness won't be enforced for `None` values
72-
:param custom_data: (optional) Custom metadata for this field.
67+
:param **kwargs: (optional) Arbitrary indirection-free metadata for
68+
this field can be supplied as additional keyword arguments and
69+
accessed as attributes of the field. Must not conflict with any
70+
existing attributes. Common metadata includes `verbose_name` and
71+
`help_text`.
7372
"""
7473
self.db_field = (db_field or name) if not primary_key else '_id'
7574

@@ -83,12 +82,19 @@ def __init__(self, db_field=None, name=None, required=False, default=None,
8382
self.primary_key = primary_key
8483
self.validation = validation
8584
self.choices = choices
86-
self.verbose_name = verbose_name
87-
self.help_text = help_text
8885
self.null = null
8986
self.sparse = sparse
9087
self._owner_document = None
91-
self.custom_data = custom_data
88+
89+
# Detect and report conflicts between metadata and base properties.
90+
conflicts = set(dir(self)) & set(kwargs)
91+
if conflicts:
92+
raise TypeError("%s already has attribute(s): %s" % (
93+
self.__class__.__name__, ', '.join(conflicts) ))
94+
95+
# Assign metadata to the instance
96+
# This efficient method is available because no __slots__ are defined.
97+
self.__dict__.update(kwargs)
9298

9399
# Adjust the appropriate creation counter, and save our local copy.
94100
if self.db_field == '_id':

mongoengine/document.py

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def modify(self, query={}, **update):
217217
Returns True if the document has been updated or False if the document
218218
in the database doesn't match the query.
219219
220-
.. note:: All unsaved changes that has been made to the document are
220+
.. note:: All unsaved changes that have been made to the document are
221221
rejected if the method returns True.
222222
223223
:param query: the update will be performed only if the document in the
@@ -341,8 +341,12 @@ def save(self, force_insert=False, validate=True, clean=True,
341341
select_dict['_id'] = object_id
342342
shard_key = self.__class__._meta.get('shard_key', tuple())
343343
for k in shard_key:
344-
actual_key = self._db_field_map.get(k, k)
345-
select_dict[actual_key] = doc[actual_key]
344+
path = self._lookup_field(k.split('.'))
345+
actual_key = [p.db_field for p in path]
346+
val = doc
347+
for ak in actual_key:
348+
val = val[ak]
349+
select_dict['.'.join(actual_key)] = val
346350

347351
def is_new_object(last_error):
348352
if last_error is not None:
@@ -403,7 +407,7 @@ def is_new_object(last_error):
403407

404408
def cascade_save(self, *args, **kwargs):
405409
"""Recursively saves any references /
406-
generic references on an objects"""
410+
generic references on the document"""
407411
_refs = kwargs.get('_refs', []) or []
408412

409413
ReferenceField = _import_class('ReferenceField')
@@ -444,7 +448,12 @@ def _object_key(self):
444448
select_dict = {'pk': self.pk}
445449
shard_key = self.__class__._meta.get('shard_key', tuple())
446450
for k in shard_key:
447-
select_dict[k] = getattr(self, k)
451+
path = self._lookup_field(k.split('.'))
452+
actual_key = [p.db_field for p in path]
453+
val = self
454+
for ak in actual_key:
455+
val = getattr(val, ak)
456+
select_dict['__'.join(actual_key)] = val
448457
return select_dict
449458

450459
def update(self, **kwargs):

mongoengine/errors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
__all__ = ('NotRegistered', 'InvalidDocumentError', 'LookUpError',
77
'DoesNotExist', 'MultipleObjectsReturned', 'InvalidQueryError',
88
'OperationError', 'NotUniqueError', 'FieldDoesNotExist',
9-
'ValidationError')
9+
'ValidationError', 'SaveConditionError')
1010

1111

1212
class NotRegistered(Exception):

mongoengine/fields.py

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -863,12 +863,11 @@ class ReferenceField(BaseField):
863863
864864
The options are:
865865
866-
* DO_NOTHING - don't do anything (default).
867-
* NULLIFY - Updates the reference to null.
868-
* CASCADE - Deletes the documents associated with the reference.
869-
* DENY - Prevent the deletion of the reference object.
870-
* PULL - Pull the reference from a :class:`~mongoengine.fields.ListField`
871-
of references
866+
* DO_NOTHING (0) - don't do anything (default).
867+
* NULLIFY (1) - Updates the reference to null.
868+
* CASCADE (2) - Deletes the documents associated with the reference.
869+
* DENY (3) - Prevent the deletion of the reference object.
870+
* PULL (4) - Pull the reference from a :class:`~mongoengine.fields.ListField` of references
872871
873872
Alternative syntax for registering delete rules (useful when implementing
874873
bi-directional delete rules)
@@ -896,6 +895,10 @@ def __init__(self, document_type, dbref=False,
896895
or as the :class:`~pymongo.objectid.ObjectId`.id .
897896
:param reverse_delete_rule: Determines what to do when the referring
898897
object is deleted
898+
899+
.. note ::
900+
A reference to an abstract document type is always stored as a
901+
:class:`~pymongo.dbref.DBRef`, regardless of the value of `dbref`.
899902
"""
900903
if not isinstance(document_type, basestring):
901904
if not issubclass(document_type, (Document, basestring)):
@@ -928,9 +931,14 @@ def __get__(self, instance, owner):
928931
self._auto_dereference = instance._fields[self.name]._auto_dereference
929932
# Dereference DBRefs
930933
if self._auto_dereference and isinstance(value, DBRef):
931-
value = self.document_type._get_db().dereference(value)
934+
if hasattr(value, 'cls'):
935+
# Dereference using the class type specified in the reference
936+
cls = get_document(value.cls)
937+
else:
938+
cls = self.document_type
939+
value = cls._get_db().dereference(value)
932940
if value is not None:
933-
instance._data[self.name] = self.document_type._from_son(value)
941+
instance._data[self.name] = cls._from_son(value)
934942

935943
return super(ReferenceField, self).__get__(instance, owner)
936944

@@ -940,21 +948,29 @@ def to_mongo(self, document):
940948
return document.id
941949
return document
942950

943-
id_field_name = self.document_type._meta['id_field']
944-
id_field = self.document_type._fields[id_field_name]
945-
946951
if isinstance(document, Document):
947952
# We need the id from the saved object to create the DBRef
948953
id_ = document.pk
949954
if id_ is None:
950955
self.error('You can only reference documents once they have'
951956
' been saved to the database')
957+
958+
# Use the attributes from the document instance, so that they
959+
# override the attributes of this field's document type
960+
cls = document
952961
else:
953962
id_ = document
963+
cls = self.document_type
964+
965+
id_field_name = cls._meta['id_field']
966+
id_field = cls._fields[id_field_name]
954967

955968
id_ = id_field.to_mongo(id_)
956-
if self.dbref:
957-
collection = self.document_type._get_collection_name()
969+
if self.document_type._meta.get('abstract'):
970+
collection = cls._get_collection_name()
971+
return DBRef(collection, id_, cls=cls._class_name)
972+
elif self.dbref:
973+
collection = cls._get_collection_name()
958974
return DBRef(collection, id_)
959975

960976
return id_
@@ -983,6 +999,14 @@ def validate(self, value):
983999
self.error('You can only reference documents once they have been '
9841000
'saved to the database')
9851001

1002+
if self.document_type._meta.get('abstract') and \
1003+
not isinstance(value, self.document_type):
1004+
self.error('%s is not an instance of abstract reference'
1005+
' type %s' % (value._class_name,
1006+
self.document_type._class_name)
1007+
)
1008+
1009+
9861010
def lookup_member(self, member_name):
9871011
return self.document_type._fields.get(member_name)
9881012

mongoengine/queryset/base.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -930,6 +930,7 @@ def read_preference(self, read_preference):
930930
validate_read_preference('read_preference', read_preference)
931931
queryset = self.clone()
932932
queryset._read_preference = read_preference
933+
queryset._cursor_obj = None # we need to re-create the cursor object whenever we apply read_preference
933934
return queryset
934935

935936
def scalar(self, *fields):
@@ -1443,8 +1444,16 @@ def _cursor_args(self):
14431444
def _cursor(self):
14441445
if self._cursor_obj is None:
14451446

1446-
self._cursor_obj = self._collection.find(self._query,
1447-
**self._cursor_args)
1447+
# In PyMongo 3+, we define the read preference on a collection
1448+
# level, not a cursor level. Thus, we need to get a cloned
1449+
# collection object using `with_options` first.
1450+
if IS_PYMONGO_3 and self._read_preference is not None:
1451+
self._cursor_obj = self._collection\
1452+
.with_options(read_preference=self._read_preference)\
1453+
.find(self._query, **self._cursor_args)
1454+
else:
1455+
self._cursor_obj = self._collection.find(self._query,
1456+
**self._cursor_args)
14481457
# Apply where clauses to cursor
14491458
if self._where_clause:
14501459
where_clause = self._sub_js_fields(self._where_clause)

0 commit comments

Comments
 (0)