MongoEngine/mongoengine — pull request #557 by b1naryth1ef (2014-01-24 23:09:42+00:00)
Title: Fixes issue with recursive embedded document errors

This is something we discovered and fixed internally that has to do with multiple levels of embedded documents which causes weird errors to be thrown that can eventually be tracked down to an error in the validation logic. Normally, a structure like this works ok:

```python

class DocB(EmbeddedDocument):
b = StringField(choices=["a", "b", "c"])

class DocA(Document):
a = EmbeddedDocumentField(DocB)

doc = DocA()
doc.a = DocB()
doc.a.b = "c"
doc.save()

# At this point, something goes wrong with the data, in this case, doc.a.b is changed to "g", thus failing the choices validation.

doc.validate()
mongoengine.errors.ValidationError: ValidationError (Also:52e2efaae1aa531824b21742) (a.b: Value must be one of ['a', 'b', 'c'])
```
This error is fairly explicit and readable error (on a side note, ValidationErrors should really throw the value that the field IS, so that one can compare the error to the value). However, in a complex application that uses multiple levels of embedded documents, there is a minor issue with the error reporting that causes things to go wacky.

```python

class DocC(EmbeddedDocument):
c = StringField(choices=["a", "b", "c"])

class DocB(EmbeddedDocument):
b = EmbeddedDocumentField(DocC)

class DocA(Document):
a = EmbeddedDocumentField(DocB)

doc = DocA()
doc.a = DocB()
doc.a.b = DocC()
doc.a.b.c = "a"
doc.save()

# Just like last time, the data at doc.a.b.c gets corrupted or invalidated
doc.validate()
mongoengine.errors.ValidationError: ValidationError (DocA:52e2f1a3e1aa53185f3a44dc) (a.b: 'DocB' object has no attribute 'pk')
```

Now with this error, something is very clearly wrong. This is a very odd and unrelated error, which can be tracked down to a weird elif clause in .validate().

With this patch, the error looks exactly as it should:
`mongoengine.errors.ValidationError: ValidationError (DocA:52e2f1a3e1aa53185f3a44dc) (a.b.c: Value must be one of ['a', 'b', 'c'])`

Enjoy, hopefully this will save someone an hour of debugging stuff.