diff --git a/docs/changelog.rst b/docs/changelog.rst index 0c767b576..81e1cf59e 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -8,6 +8,10 @@ Development =========== - (Fill this out as you fix issues and develop your features). +Changes in 0.28.1 +================= +- Fix bug related with recent updates to no_dereference context manager #2799 + Changes in 0.28.0 ================= - Fix for uuidRepresentation not read when provided in URI #2741 diff --git a/mongoengine/__init__.py b/mongoengine/__init__.py index e0bf7d76d..334ad0d08 100644 --- a/mongoengine/__init__.py +++ b/mongoengine/__init__.py @@ -29,7 +29,7 @@ ) -VERSION = (0, 28, 0) +VERSION = (0, 28, 1) def get_version(): diff --git a/mongoengine/context_managers.py b/mongoengine/context_managers.py index a4c90d476..f16753eea 100644 --- a/mongoengine/context_managers.py +++ b/mongoengine/context_managers.py @@ -20,8 +20,12 @@ ) -thread_locals = threading.local() -thread_locals.no_dereferencing_class = {} +class MyThreadLocals(threading.local): + def __init__(self): + self.no_dereferencing_class = {} + + +thread_locals = MyThreadLocals() def no_dereferencing_active_for_class(cls): diff --git a/tests/test_context_managers.py b/tests/test_context_managers.py index ac9ded729..69c8931dd 100644 --- a/tests/test_context_managers.py +++ b/tests/test_context_managers.py @@ -1,4 +1,7 @@ +import random +import time import unittest +from threading import Thread import pytest from bson import DBRef @@ -18,6 +21,29 @@ from tests.utils import MongoDBTestCase +class TestableThread(Thread): + """ + Wrapper around `threading.Thread` that propagates exceptions. + + REF: https://gist.github.com/sbrugman/59b3535ebcd5aa0e2598293cfa58b6ab + """ + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.exc = None + + def run(self): + try: + super().run() + except BaseException as e: + self.exc = e + + def join(self, timeout=None): + super().join(timeout) + if self.exc: + raise self.exc + + class TestContextManagers(MongoDBTestCase): def test_set_write_concern(self): class User(Document): @@ -172,13 +198,27 @@ class Group(Document): group = Group.objects.first() assert isinstance(group.ref, DBRef) - # make sure its still off here + # make sure it's still off here group = Group.objects.first() assert isinstance(group.ref, DBRef) group = Group.objects.first() assert isinstance(group.ref, User) + def run_in_thread(id): + time.sleep(random.uniform(0.1, 0.5)) # Force desync of threads + if id % 2 == 0: + with no_dereference(Group): + group = Group.objects.first() + assert isinstance(group.ref, DBRef) + else: + group = Group.objects.first() + assert isinstance(group.ref, User) + + threads = [TestableThread(target=run_in_thread, args=(id,)) for id in range(10)] + _ = [th.start() for th in threads] + _ = [th.join() for th in threads] + def test_no_dereference_context_manager_dbref(self): """Ensure that DBRef items in ListFields aren't dereferenced"""