Repository: MongoEngine/mongoengine

Issue:
no_sub_classes context mgr is failing silently
I noticed that the no_sub_classes context manager is not working at all but its also swallowing exceptions and thus, failing silently. In fact, see below:
```
In [1]: import mongoengine as me
   ...: me.connect()
   ...: 
   ...: class Parent(me.Document):
   ...:     name = me.StringField()
   ...:     meta = {'allow_inheritance': True}
   ...: 
   ...: class SuperParent(Parent):
   ...:     pass
   ...: 
   ...: Parent(name='John').save()
   ...: SuperParent(name='Hulk').save()
Out[1]: <SuperParent: SuperParent object>

In [2]: 
   ...: with me.context_managers.no_sub_classes(Parent):
   ...:     print 'before'
   ...:     print Parent.objects().first()	# raises InvalidDocument: Cannot encode object: <class '__main__.Parent'> but gets silenced by context
   ...:     print 'after'			# Never gets executed
   ...: print'out of context'
before
out of context
```
This is due to the no_subclasses' \__exit\__ method which is returning something that evaluates to True and by convention, the __exit__ methods of context manager swallows exceptions when doing so (https://stackoverflow.com/a/18399069)

This means that the no_sub_classes is even swallowing the AssertionError that are actually raised within the unit tests. I'll push a PR shortly.

One last thing, the context is patching the main Document class, so it is confusing to have the context manager returning the class. In fact:
```
with no_subclasses(Parent) as ParentNoSubClasses:
    print (Parent is ParentNoSubClasses) # True
```
It should only be used like:
```
with no_subclasses(Parent):
    print (Parent is ParentNoSubClasses)
```
I'd love to get rid of the "with ... as" but I'm assuming that you are against breaking changes so I won't change this. I'll push a PR to fix the issues mentioned earlier


Discussion:

Resolving patch:
diff --git a/mongoengine/context_managers.py b/mongoengine/context_managers.py
--- a/mongoengine/context_managers.py
+++ b/mongoengine/context_managers.py
@@ -145,18 +145,17 @@ def __init__(self, cls):
         :param cls: the class to turn querying sub classes on
         """
         self.cls = cls
+        self.cls_initial_subclasses = None
 
     def __enter__(self):
         """Change the objects default and _auto_dereference values."""
-        self.cls._all_subclasses = self.cls._subclasses
-        self.cls._subclasses = (self.cls,)
+        self.cls_initial_subclasses = self.cls._subclasses
+        self.cls._subclasses = (self.cls._class_name,)
         return self.cls
 
     def __exit__(self, t, value, traceback):
         """Reset the default and _auto_dereference values."""
-        self.cls._subclasses = self.cls._all_subclasses
-        delattr(self.cls, '_all_subclasses')
-        return self.cls
+        self.cls._subclasses = self.cls_initial_subclasses
 
 
 class query_counter(object):


Test patch:
diff --git a/tests/test_context_managers.py b/tests/test_context_managers.py
--- a/tests/test_context_managers.py
+++ b/tests/test_context_managers.py
@@ -140,8 +140,6 @@ class Group(Document):
     def test_no_sub_classes(self):
         class A(Document):
             x = IntField()
-            y = IntField()
-
             meta = {'allow_inheritance': True}
 
         class B(A):
@@ -152,29 +150,29 @@ class C(B):
 
         A.drop_collection()
 
-        A(x=10, y=20).save()
-        A(x=15, y=30).save()
-        B(x=20, y=40).save()
-        B(x=30, y=50).save()
-        C(x=40, y=60).save()
+        A(x=10).save()
+        A(x=15).save()
+        B(x=20).save()
+        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)
 
-        with no_sub_classes(A) as A:
+        with no_sub_classes(A):
             self.assertEqual(A.objects.count(), 2)
 
             for obj in A.objects:
                 self.assertEqual(obj.__class__, A)
 
-        with no_sub_classes(B) as B:
+        with no_sub_classes(B):
             self.assertEqual(B.objects.count(), 2)
 
             for obj in B.objects:
                 self.assertEqual(obj.__class__, B)
 
-        with no_sub_classes(C) as C:
+        with no_sub_classes(C):
             self.assertEqual(C.objects.count(), 1)
 
             for obj in C.objects:
@@ -185,6 +183,32 @@ class C(B):
         self.assertEqual(B.objects.count(), 3)
         self.assertEqual(C.objects.count(), 1)
 
+    def test_no_sub_classes_modification_to_document_class_are_temporary(self):
+        class A(Document):
+            x = IntField()
+            meta = {'allow_inheritance': True}
+
+        class B(A):
+            z = IntField()
+
+        self.assertEqual(A._subclasses, ('A', 'A.B'))
+        with no_sub_classes(A):
+            self.assertEqual(A._subclasses, ('A',))
+        self.assertEqual(A._subclasses, ('A', 'A.B'))
+
+        self.assertEqual(B._subclasses, ('A.B',))
+        with no_sub_classes(B):
+            self.assertEqual(B._subclasses, ('A.B',))
+        self.assertEqual(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 no_sub_classes(User):
+                raise TypeError()
+
     def test_query_counter(self):
         connect('mongoenginetest')
         db = get_db()