Skip to content

Commit eb4a047

Browse files
committed
PYTHON-1799 Don't iterate _ENCODERS dict when encoding bson
1 parent 2bdc188 commit eb4a047

File tree

3 files changed

+37
-1
lines changed

3 files changed

+37
-1
lines changed

bson/__init__.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -752,6 +752,9 @@ def _encode_maxkey(name, dummy0, dummy1, dummy2):
752752
_ENCODERS[long] = _encode_long
753753

754754

755+
_BUILT_IN_TYPES = tuple(t for t in _ENCODERS)
756+
757+
755758
def _name_value_to_bson(name, value, check_keys, opts,
756759
in_fallback_call=False):
757760
"""Encode a single name, value pair."""
@@ -783,7 +786,7 @@ def _name_value_to_bson(name, value, check_keys, opts,
783786

784787
# If all else fails test each base type. This will only happen once for
785788
# a subtype of a supported base type.
786-
for base in _ENCODERS:
789+
for base in _BUILT_IN_TYPES:
787790
if isinstance(value, base):
788791
func = _ENCODERS[base]
789792
# Cache this type for faster subsequent lookup.

test/test_bson.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@
5050
utc)
5151

5252
from test import qcheck, SkipTest, unittest
53+
from test.utils import ExceptionCatchingThread
5354

5455
if PY3:
5556
long = int
@@ -904,6 +905,24 @@ def test_bad_id_keys(self):
904905
{"_id": {'$oid': "52d0b971b3ba219fdeb4170e"}}, True)
905906
BSON.encode({"_id": {'$oid': "52d0b971b3ba219fdeb4170e"}})
906907

908+
def test_bson_encode_thread_safe(self):
909+
910+
def target(i):
911+
for j in range(1000):
912+
my_int = type('MyInt_%s_%s' % (i, j), (int,), {})
913+
bson.BSON.encode({'my_int': my_int()})
914+
915+
threads = [ExceptionCatchingThread(target=target, args=(i,))
916+
for i in range(3)]
917+
for t in threads:
918+
t.start()
919+
920+
for t in threads:
921+
t.join()
922+
923+
for t in threads:
924+
self.assertIsNone(t.exc)
925+
907926

908927
class TestCodecOptions(unittest.TestCase):
909928
def test_document_class(self):

test/utils.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,3 +683,17 @@ def enable_replication(client):
683683
secondary = single_client(host, port)
684684
secondary.admin.command('configureFailPoint', 'stopReplProducer',
685685
mode='off')
686+
687+
688+
class ExceptionCatchingThread(threading.Thread):
689+
"""A thread that stores any exception encountered from run()."""
690+
def __init__(self, *args, **kwargs):
691+
self.exc = None
692+
super(ExceptionCatchingThread, self).__init__(*args, **kwargs)
693+
694+
def run(self):
695+
try:
696+
super(ExceptionCatchingThread, self).run()
697+
except BaseException as exc:
698+
self.exc = exc
699+
raise

0 commit comments

Comments
 (0)