Skip to content

Commit 79dfcdb

Browse files
authored
Merge pull request #2800 from bagerard/bug_no_deref_thread_local
Fix bug in mutable thread local related with no_dereference ctx manager
2 parents 5e0a678 + 7b23027 commit 79dfcdb

File tree

4 files changed

+52
-4
lines changed

4 files changed

+52
-4
lines changed

docs/changelog.rst

+4
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ Development
88
===========
99
- (Fill this out as you fix issues and develop your features).
1010

11+
Changes in 0.28.1
12+
=================
13+
- Fix bug related with recent updates to no_dereference context manager #2799
14+
1115
Changes in 0.28.0
1216
=================
1317
- Fix for uuidRepresentation not read when provided in URI #2741

mongoengine/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929
)
3030

3131

32-
VERSION = (0, 28, 0)
32+
VERSION = (0, 28, 1)
3333

3434

3535
def get_version():

mongoengine/context_managers.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,12 @@
2020
)
2121

2222

23-
thread_locals = threading.local()
24-
thread_locals.no_dereferencing_class = {}
23+
class MyThreadLocals(threading.local):
24+
def __init__(self):
25+
self.no_dereferencing_class = {}
26+
27+
28+
thread_locals = MyThreadLocals()
2529

2630

2731
def no_dereferencing_active_for_class(cls):

tests/test_context_managers.py

+41-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1+
import random
2+
import time
13
import unittest
4+
from threading import Thread
25

36
import pytest
47
from bson import DBRef
@@ -18,6 +21,29 @@
1821
from tests.utils import MongoDBTestCase
1922

2023

24+
class TestableThread(Thread):
25+
"""
26+
Wrapper around `threading.Thread` that propagates exceptions.
27+
28+
REF: https://gist.github.com/sbrugman/59b3535ebcd5aa0e2598293cfa58b6ab
29+
"""
30+
31+
def __init__(self, *args, **kwargs):
32+
super().__init__(*args, **kwargs)
33+
self.exc = None
34+
35+
def run(self):
36+
try:
37+
super().run()
38+
except BaseException as e:
39+
self.exc = e
40+
41+
def join(self, timeout=None):
42+
super().join(timeout)
43+
if self.exc:
44+
raise self.exc
45+
46+
2147
class TestContextManagers(MongoDBTestCase):
2248
def test_set_write_concern(self):
2349
class User(Document):
@@ -172,13 +198,27 @@ class Group(Document):
172198
group = Group.objects.first()
173199
assert isinstance(group.ref, DBRef)
174200

175-
# make sure its still off here
201+
# make sure it's still off here
176202
group = Group.objects.first()
177203
assert isinstance(group.ref, DBRef)
178204

179205
group = Group.objects.first()
180206
assert isinstance(group.ref, User)
181207

208+
def run_in_thread(id):
209+
time.sleep(random.uniform(0.1, 0.5)) # Force desync of threads
210+
if id % 2 == 0:
211+
with no_dereference(Group):
212+
group = Group.objects.first()
213+
assert isinstance(group.ref, DBRef)
214+
else:
215+
group = Group.objects.first()
216+
assert isinstance(group.ref, User)
217+
218+
threads = [TestableThread(target=run_in_thread, args=(id,)) for id in range(10)]
219+
_ = [th.start() for th in threads]
220+
_ = [th.join() for th in threads]
221+
182222
def test_no_dereference_context_manager_dbref(self):
183223
"""Ensure that DBRef items in ListFields aren't dereferenced"""
184224

0 commit comments

Comments
 (0)