PYTHON-2133 Remove py2 support from test

Also delete bson/py3compat.py
This commit is contained in:
Bernie Hackett 2021-01-20 09:40:36 -08:00
parent 6c2d629006
commit a72e8b8823
37 changed files with 203 additions and 690 deletions

View File

@ -14,13 +14,7 @@
"""A BSON wrapper for long (int in python3)"""
from bson.py3compat import PY3
if PY3:
long = int
class Int64(long):
class Int64(int):
"""Representation of the BSON int64 type.
This is necessary because every integral number is an :class:`int` in

View File

@ -1,107 +0,0 @@
# Copyright 2009-present MongoDB, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you
# may not use this file except in compliance with the License. You
# may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
# implied. See the License for the specific language governing
# permissions and limitations under the License.
"""Utility functions and definitions for python3 compatibility."""
import sys
PY3 = sys.version_info[0] == 3
if PY3:
import codecs
import collections.abc as abc
import _thread as thread
from abc import ABC, abstractmethod
from io import BytesIO as StringIO
def abstractproperty(func):
return property(abstractmethod(func))
MAXSIZE = sys.maxsize
imap = map
def b(s):
# BSON and socket operations deal in binary data. In
# python 3 that means instances of `bytes`. In python
# 2.7 you can create an alias for `bytes` using
# the b prefix (e.g. b'foo').
# See http://python3porting.com/problems.html#nicer-solutions
return codecs.latin_1_encode(s)[0]
def bytes_from_hex(h):
return bytes.fromhex(h)
def iteritems(d):
return iter(d.items())
def itervalues(d):
return iter(d.values())
def reraise(exctype, value, trace=None):
raise exctype(str(value)).with_traceback(trace)
def reraise_instance(exc_instance, trace=None):
raise exc_instance.with_traceback(trace)
def _unicode(s):
return s
text_type = str
string_type = str
integer_types = int
else:
import collections as abc
import thread
from abc import ABCMeta, abstractproperty
from itertools import imap
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
ABC = ABCMeta('ABC', (object,), {})
MAXSIZE = sys.maxint
def b(s):
# See comments above. In python 2.x b('foo') is just 'foo'.
return s
def bytes_from_hex(h):
return h.decode('hex')
def iteritems(d):
return d.iteritems()
def itervalues(d):
return d.itervalues()
def reraise(exctype, value, trace=None):
_reraise(exctype, str(value), trace)
def reraise_instance(exc_instance, trace=None):
_reraise(exc_instance, None, trace)
# "raise x, y, z" raises SyntaxError in Python 3
exec("""def _reraise(exc, value, trace):
raise exc, value, trace
""")
_unicode = unicode
string_type = basestring
text_type = unicode
integer_types = (int, long)

View File

@ -1,193 +0,0 @@
# Backport of the threading.Barrier class from python 3.8, with small
# changes to support python 2.7.
# https://github.com/python/cpython/blob/v3.8.2/Lib/threading.py#L562-L728
from threading import (Condition,
Lock)
from pymongo.monotonic import time as _time
# Backport Condition.wait_for from 3.8.2
# https://github.com/python/cpython/blob/v3.8.2/Lib/threading.py#L318-L339
def wait_for(condition, predicate, timeout=None):
"""Wait until a condition evaluates to True.
predicate should be a callable which result will be interpreted as a
boolean value. A timeout may be provided giving the maximum time to
wait.
"""
endtime = None
waittime = timeout
result = predicate()
while not result:
if waittime is not None:
if endtime is None:
endtime = _time() + waittime
else:
waittime = endtime - _time()
if waittime <= 0:
break
condition.wait(waittime)
result = predicate()
return result
# A barrier class. Inspired in part by the pthread_barrier_* api and
# the CyclicBarrier class from Java. See
# http://sourceware.org/pthreads-win32/manual/pthread_barrier_init.html and
# http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/
# CyclicBarrier.html
# for information.
# We maintain two main states, 'filling' and 'draining' enabling the barrier
# to be cyclic. Threads are not allowed into it until it has fully drained
# since the previous cycle. In addition, a 'resetting' state exists which is
# similar to 'draining' except that threads leave with a BrokenBarrierError,
# and a 'broken' state in which all threads get the exception.
class Barrier(object):
"""Implements a Barrier.
Useful for synchronizing a fixed number of threads at known synchronization
points. Threads block on 'wait()' and are simultaneously awoken once they
have all made that call.
"""
def __init__(self, parties, action=None, timeout=None):
"""Create a barrier, initialised to 'parties' threads.
'action' is a callable which, when supplied, will be called by one of
the threads after they have all entered the barrier and just prior to
releasing them all. If a 'timeout' is provided, it is used as the
default for all subsequent 'wait()' calls.
"""
self._cond = Condition(Lock())
self._action = action
self._timeout = timeout
self._parties = parties
self._state = 0 #0 filling, 1, draining, -1 resetting, -2 broken
self._count = 0
def wait(self, timeout=None):
"""Wait for the barrier.
When the specified number of threads have started waiting, they are all
simultaneously awoken. If an 'action' was provided for the barrier, one
of the threads will have executed that callback prior to returning.
Returns an individual index number from 0 to 'parties-1'.
"""
if timeout is None:
timeout = self._timeout
with self._cond:
self._enter() # Block while the barrier drains.
index = self._count
self._count += 1
try:
if index + 1 == self._parties:
# We release the barrier
self._release()
else:
# We wait until someone releases us
self._wait(timeout)
return index
finally:
self._count -= 1
# Wake up any threads waiting for barrier to drain.
self._exit()
# Block until the barrier is ready for us, or raise an exception
# if it is broken.
def _enter(self):
while self._state in (-1, 1):
# It is draining or resetting, wait until done
self._cond.wait()
#see if the barrier is in a broken state
if self._state < 0:
raise BrokenBarrierError
assert self._state == 0
# Optionally run the 'action' and release the threads waiting
# in the barrier.
def _release(self):
try:
if self._action:
self._action()
# enter draining state
self._state = 1
self._cond.notify_all()
except:
#an exception during the _action handler. Break and reraise
self._break()
raise
# Wait in the barrier until we are released. Raise an exception
# if the barrier is reset or broken.
def _wait(self, timeout):
if not wait_for(self._cond, lambda : self._state != 0, timeout):
#timed out. Break the barrier
self._break()
raise BrokenBarrierError
if self._state < 0:
raise BrokenBarrierError
assert self._state == 1
# If we are the last thread to exit the barrier, signal any threads
# waiting for the barrier to drain.
def _exit(self):
if self._count == 0:
if self._state in (-1, 1):
#resetting or draining
self._state = 0
self._cond.notify_all()
def reset(self):
"""Reset the barrier to the initial state.
Any threads currently waiting will get the BrokenBarrier exception
raised.
"""
with self._cond:
if self._count > 0:
if self._state == 0:
#reset the barrier, waking up threads
self._state = -1
elif self._state == -2:
#was broken, set it to reset state
#which clears when the last thread exits
self._state = -1
else:
self._state = 0
self._cond.notify_all()
def abort(self):
"""Place the barrier into a 'broken' state.
Useful in case of error. Any currently waiting threads and threads
attempting to 'wait()' will have BrokenBarrierError raised.
"""
with self._cond:
self._break()
def _break(self):
# An internal error was detected. The barrier is set to
# a broken state all parties awakened.
self._state = -2
self._cond.notify_all()
@property
def parties(self):
"""Return the number of threads required to trip the barrier."""
return self._parties
@property
def n_waiting(self):
"""Return the number of threads currently waiting at the barrier."""
# We don't need synchronization here since this is an ephemeral result
# anyway. It returns the correct value in the steady state.
if self._state == 0:
return self._count
return 0
@property
def broken(self):
"""Return True if the barrier is in a broken state."""
return self._state == -2
# exception raised by the Barrier class
class BrokenBarrierError(RuntimeError):
pass

View File

@ -12,22 +12,18 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import random
import traceback
import datetime
import random
import re
import sys
import traceback
sys.path[0:0] = [""]
from bson.binary import Binary
from bson.dbref import DBRef
from bson.objectid import ObjectId
from bson.py3compat import MAXSIZE, PY3, iteritems
from bson.son import SON
if PY3:
unichr = chr
gen_target = 100
reduction_attempts = 10
examples = 5
@ -59,7 +55,7 @@ def gen_int():
def gen_float():
return lambda: (random.random() - 0.5) * MAXSIZE
return lambda: (random.random() - 0.5) * sys.maxsize
def gen_boolean():
@ -74,12 +70,8 @@ def gen_printable_string(gen_length):
return lambda: "".join(gen_list(gen_printable_char(), gen_length)())
if PY3:
def gen_char(set=None):
return lambda: bytes([random.randint(0, 255)])
else:
def gen_char(set=None):
return lambda: chr(random.randint(0, 255))
def gen_char(set=None):
return lambda: bytes([random.randint(0, 255)])
def gen_string(gen_length):
@ -87,7 +79,7 @@ def gen_string(gen_length):
def gen_unichar():
return lambda: unichr(random.randint(1, 0xFFF))
return lambda: chr(random.randint(1, 0xFFF))
def gen_unicode(gen_length):
@ -150,15 +142,9 @@ def gen_dbref():
def gen_mongo_value(depth, ref):
bintype = Binary
if PY3:
# If we used Binary in python3 tests would fail since we
# decode BSON binary subtype 0 to bytes. Testing this with
# bytes in python3 makes a lot more sense.
bintype = bytes
choices = [gen_unicode(gen_range(0, 50)),
gen_printable_string(gen_range(0, 50)),
my_map(gen_string(gen_range(0, 1000)), bintype),
my_map(gen_string(gen_range(0, 1000)), bytes),
gen_int(),
gen_float(),
gen_boolean(),
@ -195,7 +181,7 @@ def simplify(case): # TODO this is a hack
return (True, simplified)
else:
# simplify a value
simplified_items = list(iteritems(simplified))
simplified_items = list(simplified.items())
if not len(simplified_items):
return (False, case)
(key, value) = random.choice(simplified_items)

View File

@ -17,6 +17,7 @@
import array
import base64
import copy
import mmap
import pickle
import platform
import sys
@ -29,11 +30,12 @@ import bson
from bson import decode, encode
from bson.binary import *
from bson.codec_options import CodecOptions
from bson.py3compat import PY3
from bson.son import SON
from pymongo.common import validate_uuid_representation
from pymongo.mongo_client import MongoClient
from pymongo.write_concern import WriteConcern
from test import client_context, unittest, IntegrationTest
from test.utils import ignore_deprecations
@ -328,14 +330,9 @@ class TestBinary(unittest.TestCase):
b1 = Binary(b'123', 2)
# For testing backwards compatibility with pre-2.4 pymongo
if PY3:
p = (b"\x80\x03cbson.binary\nBinary\nq\x00C\x03123q\x01\x85q"
b"\x02\x81q\x03}q\x04X\x10\x00\x00\x00_Binary__subtypeq"
b"\x05K\x02sb.")
else:
p = (b"ccopy_reg\n_reconstructor\np0\n(cbson.binary\nBinary\np1\nc"
b"__builtin__\nstr\np2\nS'123'\np3\ntp4\nRp5\n(dp6\nS'_Binary"
b"__subtype'\np7\nI2\nsb.")
p = (b"\x80\x03cbson.binary\nBinary\nq\x00C\x03123q\x01\x85q"
b"\x02\x81q\x03}q\x04X\x10\x00\x00\x00_Binary__subtypeq"
b"\x05K\x02sb.")
if not sys.version.startswith('3.0'):
self.assertEqual(b1, pickle.loads(p))
@ -357,16 +354,11 @@ class TestBinary(unittest.TestCase):
self.assertEqual(b0, Binary(memoryview(b'123'), 2))
self.assertEqual(b0, Binary(bytearray(b'123'), 2))
# mmap.mmap and array.array only expose the
# buffer interface in python 3.x
if PY3:
# No mmap module in Jython
import mmap
with mmap.mmap(-1, len(b'123')) as mm:
mm.write(b'123')
mm.seek(0)
self.assertEqual(b0, Binary(mm, 2))
self.assertEqual(b0, Binary(array.array('B', b'123'), 2))
with mmap.mmap(-1, len(b'123')) as mm:
mm.write(b'123')
mm.seek(0)
self.assertEqual(b0, Binary(mm, 2))
self.assertEqual(b0, Binary(array.array('B', b'123'), 2))
class TestUuidSpecExplicitCoding(unittest.TestCase):
@ -377,9 +369,7 @@ class TestUuidSpecExplicitCoding(unittest.TestCase):
@staticmethod
def _hex_to_bytes(hexstring):
if PY3:
return bytes.fromhex(hexstring)
return hexstring.decode("hex")
return bytes.fromhex(hexstring)
# Explicit encoding prose test #1
def test_encoding_1(self):
@ -482,9 +472,7 @@ class TestUuidSpecImplicitCoding(IntegrationTest):
@staticmethod
def _hex_to_bytes(hexstring):
if PY3:
return bytes.fromhex(hexstring)
return hexstring.decode("hex")
return bytes.fromhex(hexstring)
def _get_coll_w_uuid_rep(self, uuid_rep):
codec_options = self.client.codec_options.with_options(

View File

@ -16,14 +16,19 @@
"""Test the bson module."""
import array
import collections
import datetime
import mmap
import os
import re
import sys
import tempfile
import uuid
from collections import abc, OrderedDict
from io import BytesIO
sys.path[0:0] = [""]
import bson
@ -42,23 +47,18 @@ from bson.codec_options import CodecOptions
from bson.int64 import Int64
from bson.objectid import ObjectId
from bson.dbref import DBRef
from bson.py3compat import abc, iteritems, PY3, StringIO, text_type
from bson.son import SON
from bson.timestamp import Timestamp
from bson.errors import (InvalidBSON,
InvalidDocument,
InvalidStringData)
InvalidDocument)
from bson.max_key import MaxKey
from bson.min_key import MinKey
from bson.tz_util import (FixedOffset,
utc)
from test import qcheck, SkipTest, unittest
from test import qcheck, unittest
from test.utils import ExceptionCatchingThread
if PY3:
long = int
class NotADict(abc.MutableMapping):
"""Non-dict type that implements the mapping protocol."""
@ -134,7 +134,7 @@ class TestBSON(unittest.TestCase):
helper({})
helper({"test": u"hello"})
self.assertTrue(isinstance(decoder(encoder(
{"hello": "world"}))["hello"], text_type))
{"hello": "world"}))["hello"], str))
helper({"mike": -10120})
helper({"long": Int64(10)})
helper({"really big long": 2147483648})
@ -293,7 +293,7 @@ class TestBSON(unittest.TestCase):
b"\x6f\x20\x77\x6F\x72\x6C\x64\x00\x00"
b"\x05\x00\x00\x00\x00")))
self.assertEqual([{"test": u"hello world"}, {}],
list(decode_file_iter(StringIO(
list(decode_file_iter(BytesIO(
b"\x1B\x00\x00\x00\x0E\x74\x65\x73\x74"
b"\x00\x0C\x00\x00\x00\x68\x65\x6C\x6C"
b"\x6f\x20\x77\x6F\x72\x6C\x64\x00\x00"
@ -305,14 +305,11 @@ class TestBSON(unittest.TestCase):
self.assertEqual(docs, decode_all(bytearray(bs)))
self.assertEqual(docs, decode_all(memoryview(bs)))
self.assertEqual(docs, decode_all(memoryview(b'1' + bs + b'1')[1:-1]))
if PY3:
import array
import mmap
self.assertEqual(docs, decode_all(array.array('B', bs)))
with mmap.mmap(-1, len(bs)) as mm:
mm.write(bs)
mm.seek(0)
self.assertEqual(docs, decode_all(mm))
self.assertEqual(docs, decode_all(array.array('B', bs)))
with mmap.mmap(-1, len(bs)) as mm:
mm.write(bs)
mm.seek(0)
self.assertEqual(docs, decode_all(mm))
def test_decode_buffer_protocol(self):
doc = {'foo': 'bar'}
@ -321,21 +318,18 @@ class TestBSON(unittest.TestCase):
self.assertEqual(doc, decode(bytearray(bs)))
self.assertEqual(doc, decode(memoryview(bs)))
self.assertEqual(doc, decode(memoryview(b'1' + bs + b'1')[1:-1]))
if PY3:
import array
import mmap
self.assertEqual(doc, decode(array.array('B', bs)))
with mmap.mmap(-1, len(bs)) as mm:
mm.write(bs)
mm.seek(0)
self.assertEqual(doc, decode(mm))
self.assertEqual(doc, decode(array.array('B', bs)))
with mmap.mmap(-1, len(bs)) as mm:
mm.write(bs)
mm.seek(0)
self.assertEqual(doc, decode(mm))
def test_invalid_decodes(self):
# Invalid object size (not enough bytes in document for even
# an object size of first object.
# NOTE: decode_all and decode_iter don't care, not sure if they should?
self.assertRaises(InvalidBSON, list,
decode_file_iter(StringIO(b"\x1B")))
decode_file_iter(BytesIO(b"\x1B")))
bad_bsons = [
# An object size that's too small to even include the object size,
@ -366,7 +360,7 @@ class TestBSON(unittest.TestCase):
with self.assertRaises(InvalidBSON, msg=msg):
list(decode_iter(data))
with self.assertRaises(InvalidBSON, msg=msg):
list(decode_file_iter(StringIO(data)))
list(decode_file_iter(BytesIO(data)))
with tempfile.TemporaryFile() as scratch:
scratch.write(data)
scratch.seek(0, os.SEEK_SET)
@ -498,10 +492,7 @@ class TestBSON(unittest.TestCase):
# Since `bytes` are stored as Binary you can't use them
# as keys in python 3.x. Using binary data as a key makes
# no sense in BSON anyway and little sense in python.
if PY3:
self.assertRaises(InvalidDocument, encode, doc)
else:
self.assertTrue(encode(doc))
self.assertRaises(InvalidDocument, encode, doc)
def test_datetime_encode_decode(self):
# Negative timestamps
@ -604,13 +595,6 @@ class TestBSON(unittest.TestCase):
self.assertEqual(d, decode(encode(d)))
def test_bad_encode(self):
if not PY3:
# Python3 treats this as a unicode string which won't raise
# an exception. If we passed the string as bytes instead we
# still wouldn't get an error since we store bytes as BSON
# binary subtype 0.
self.assertRaises(InvalidStringData, encode,
{"lalala": '\xf4\xe0\xf0\xe1\xc0 Color Touch'})
# Work around what seems like a regression in python 3.5.0.
# See http://bugs.python.org/issue25222
if sys.version_info[:2] < (3, 5):
@ -622,13 +606,13 @@ class TestBSON(unittest.TestCase):
self.assertRaises(Exception, encode, evil_data)
def test_overflow(self):
self.assertTrue(encode({"x": long(9223372036854775807)}))
self.assertTrue(encode({"x": 9223372036854775807}))
self.assertRaises(OverflowError, encode,
{"x": long(9223372036854775808)})
{"x": 9223372036854775808})
self.assertTrue(encode({"x": long(-9223372036854775808)}))
self.assertTrue(encode({"x": -9223372036854775808}))
self.assertRaises(OverflowError, encode,
{"x": long(-9223372036854775809)})
{"x": -9223372036854775809})
def test_small_long_encode_decode(self):
encoded1 = encode({'x': 256})
@ -682,25 +666,10 @@ class TestBSON(unittest.TestCase):
# b'a\xe9' == u"aé".encode("iso-8859-1")
iso8859_bytes = b'a\xe9'
y = {"hello": iso8859_bytes}
if PY3:
# Stored as BSON binary subtype 0.
out = decode(encode(y))
self.assertTrue(isinstance(out['hello'], bytes))
self.assertEqual(out['hello'], iso8859_bytes)
else:
# Python 2.
try:
encode(y)
except InvalidStringData as e:
self.assertTrue(repr(iso8859_bytes) in str(e))
# The next two tests only make sense in python 2.x since
# you can't use `bytes` type as document keys in python 3.x.
x = {u"aéあ".encode("utf-8"): u"aéあ".encode("utf-8")}
self.assertEqual(w, decode(encode(x)))
z = {iso8859_bytes: "hello"}
self.assertRaises(InvalidStringData, encode, z)
# Stored as BSON binary subtype 0.
out = decode(encode(y))
self.assertTrue(isinstance(out['hello'], bytes))
self.assertEqual(out['hello'], iso8859_bytes)
def test_null_character(self):
doc = {"a": "\x00"}
@ -767,24 +736,20 @@ class TestBSON(unittest.TestCase):
class _myfloat(float):
pass
class _myunicode(text_type):
class _myunicode(str):
pass
d = {'a': _myint(42), 'b': _myfloat(63.9),
'c': _myunicode('hello world')
}
d2 = decode(encode(d))
for key, value in iteritems(d2):
for key, value in d2.items():
orig_value = d[key]
orig_type = orig_value.__class__.__bases__[0]
self.assertEqual(type(value), orig_type)
self.assertEqual(value, orig_type(value))
def test_ordered_dict(self):
try:
from collections import OrderedDict
except ImportError:
raise SkipTest("No OrderedDict")
d = OrderedDict([("one", 1), ("two", 2), ("three", 3), ("four", 4)])
self.assertEqual(
d, decode(encode(d), CodecOptions(document_class=OrderedDict)))

View File

@ -33,7 +33,6 @@ from bson.decimal128 import Decimal128
from bson.dbref import DBRef
from bson.errors import InvalidBSON, InvalidId
from bson.json_util import JSONMode
from bson.py3compat import text_type, b
from bson.son import SON
from test import unittest
@ -56,7 +55,7 @@ _NON_PARSE_ERRORS = set([
_DEPRECATED_BSON_TYPES = {
# Symbol
'0x0E': text_type,
'0x0E': str,
# Undefined
'0x06': type(None),
# DBPointer
@ -122,7 +121,7 @@ def create_test(case_spec):
encode_extjson = to_extjson
encode_bson = to_bson
cB = binascii.unhexlify(b(valid_case['canonical_bson']))
cB = binascii.unhexlify(valid_case['canonical_bson'].encode('utf8'))
cEJ = valid_case['canonical_extjson']
rEJ = valid_case.get('relaxed_extjson')
dEJ = valid_case.get('degenerate_extjson')
@ -139,7 +138,7 @@ def create_test(case_spec):
if deprecated:
if 'converted_bson' in valid_case:
converted_bson = binascii.unhexlify(
b(valid_case['converted_bson']))
valid_case['converted_bson'].encode('utf8'))
self.assertEqual(encode_bson(decoded_bson), converted_bson)
self.assertJsonEqual(
encode_extjson(decode_bson(converted_bson)),
@ -167,7 +166,7 @@ def create_test(case_spec):
# Test round-tripping degenerate bson.
if 'degenerate_bson' in valid_case:
dB = binascii.unhexlify(b(valid_case['degenerate_bson']))
dB = binascii.unhexlify(valid_case['degenerate_bson'].encode('utf8'))
self.assertEqual(encode_bson(decode_bson(dB)), cB)
# Test round-tripping degenerate extended json.
@ -186,7 +185,7 @@ def create_test(case_spec):
for decode_error_case in case_spec.get('decodeErrors', []):
with self.assertRaises(InvalidBSON):
decode_bson(
binascii.unhexlify(b(decode_error_case['bson'])))
binascii.unhexlify(decode_error_case['bson'].encode('utf8')))
for parse_error_case in case_spec.get('parseErrors', []):
if bson_type == '0x13':

View File

@ -23,7 +23,6 @@ import threading
import time
import uuid
from contextlib import contextmanager
from itertools import product
sys.path[0:0] = ['']
@ -33,7 +32,6 @@ from bson.binary import (ALL_UUID_REPRESENTATIONS,
Binary,
STANDARD,
PYTHON_LEGACY)
from bson.py3compat import iteritems
from bson.raw_bson import DEFAULT_RAW_BSON_OPTIONS, RawBSONDocument
from pymongo import MongoClient
@ -1093,7 +1091,7 @@ class TestAllScenarios(unittest.TestCase):
def assert_dict_is_subset(self, superdict, subdict):
"""Check that subdict is a subset of superdict."""
exempt_fields = ["documentKey", "_id", "getMore"]
for key, value in iteritems(subdict):
for key, value in subdict.items():
if key not in superdict:
self.fail('Key %s not found in %s' % (key, superdict))
if isinstance(value, dict):
@ -1111,7 +1109,7 @@ class TestAllScenarios(unittest.TestCase):
def check_event(self, event, expectation_dict):
if event is None:
self.fail()
for key, value in iteritems(expectation_dict):
for key, value in expectation_dict.items():
if isinstance(value, dict):
self.assert_dict_is_subset(getattr(event, key), value)
else:
@ -1149,9 +1147,9 @@ def get_change_stream(client, scenario_def, test):
cs_pipeline = test["changeStreamPipeline"]
options = test["changeStreamOptions"]
cs_options = {}
for key, value in iteritems(options):
for key, value in options.items():
cs_options[camel_to_snake(key)] = value
# Create and return change stream
return cs_target.watch(pipeline=cs_pipeline, **cs_options)
@ -1203,12 +1201,12 @@ def create_test(scenario_def, test):
for change, expected_changes in zip(changes, test["result"]["success"]):
self.assert_dict_is_subset(change, expected_changes)
self.assertEqual(len(changes), len(test["result"]["success"]))
finally:
# Check for expected events
results = self.listener.results
for idx, expectation in enumerate(test.get("expectations", [])):
for event_type, event_desc in iteritems(expectation):
for event_type, event_desc in expectation.items():
results_key = event_type.split("_")[1]
event = results[results_key][idx] if len(results[results_key]) > idx else None
self.check_event(event, event_desc)

View File

@ -24,6 +24,7 @@ import socket
import struct
import sys
import time
import _thread as thread
import threading
import warnings
@ -31,7 +32,6 @@ sys.path[0:0] = [""]
from bson import encode
from bson.codec_options import CodecOptions, TypeEncoder, TypeRegistry
from bson.py3compat import thread
from bson.son import SON
from bson.tz_util import utc
import pymongo
@ -90,7 +90,6 @@ from test.utils import (assertRaisesExactly,
rs_client,
rs_or_single_client,
rs_or_single_client_noauth,
server_is_master_with_slave,
single_client,
wait_until)

View File

@ -19,7 +19,6 @@
import contextlib
import re
import sys
import threading
from codecs import utf_8_decode
from collections import defaultdict
@ -32,7 +31,6 @@ from bson.regex import Regex
from bson.code import Code
from bson.codec_options import CodecOptions
from bson.objectid import ObjectId
from bson.py3compat import itervalues
from bson.son import SON
from pymongo import (ASCENDING, DESCENDING, GEO2D,
GEOHAYSTACK, GEOSPHERE, HASHED, TEXT)
@ -376,7 +374,7 @@ class TestCollection(IntegrationTest):
reindexed = db.test.reindex()
if 'raw' in reindexed:
# mongos
for result in itervalues(reindexed['raw']):
for result in reindexed['raw'].values():
check_result(result)
else:
check_result(reindexed)
@ -1349,12 +1347,6 @@ class TestCollection(IntegrationTest):
self.assertIn('E11000 duplicate key error',
str(ctx.exception))
if sys.version_info[0] == 2:
# Test unicode(error) conversion.
self.assertIn('E11000 duplicate key error',
unicode(ctx.exception))
def test_wtimeout(self):
# Ensure setting wtimeout doesn't disable write concern altogether.
# See SERVER-12596.

View File

@ -14,14 +14,11 @@
"""Test the collection module."""
import json
import os
import re
import sys
sys.path[0:0] = [""]
from bson.py3compat import iteritems
from pymongo import operations, WriteConcern
from pymongo.command_cursor import CommandCursor
from pymongo.cursor import Cursor
@ -35,7 +32,7 @@ from pymongo.operations import (InsertOne,
UpdateOne,
UpdateMany)
from test import unittest, client_context, IntegrationTest
from test import unittest, IntegrationTest
from test.utils import (camel_to_snake, camel_to_upper_camel,
camel_to_snake_args, drop_collections, TestCreator)
@ -113,7 +110,7 @@ def run_operation(collection, test):
# PyMongo accepts sort as list of tuples.
if arg_name == "sort":
sort_dict = arguments[arg_name]
arguments[arg_name] = list(iteritems(sort_dict))
arguments[arg_name] = list(sort_dict.items())
# Named "key" instead not fieldName.
if arg_name == "fieldName":
arguments["key"] = arguments.pop(arg_name)

View File

@ -27,7 +27,6 @@ sys.path[0:0] = [""]
from bson import decode_all
from bson.code import Code
from bson.py3compat import PY3
from bson.son import SON
from pymongo import (ASCENDING,
DESCENDING,
@ -40,7 +39,6 @@ from pymongo.errors import (ConfigurationError,
InvalidOperation,
OperationFailure)
from pymongo.read_concern import ReadConcern
from pymongo.read_preferences import ReadPreference
from test import (client_context,
unittest,
IntegrationTest)
@ -49,9 +47,6 @@ from test.utils import (EventListener,
rs_or_single_client,
WhiteListEventListener)
if PY3:
long = int
class TestCursor(IntegrationTest):
def test_deepcopy_cursor_littered_with_regexes(self):
@ -167,7 +162,7 @@ class TestCursor(IntegrationTest):
coll.insert_one({"amalia": 2})
coll.find().max_time_ms(None)
coll.find().max_time_ms(long(1))
coll.find().max_time_ms(1)
cursor = coll.find().max_time_ms(999)
self.assertEqual(999, cursor._Cursor__max_time_ms)
@ -215,7 +210,7 @@ class TestCursor(IntegrationTest):
coll.insert_one({"amalia": 2})
coll.find().max_await_time_ms(None)
coll.find().max_await_time_ms(long(1))
coll.find().max_await_time_ms(1)
# When cursor is not tailable_await
cursor = coll.find()
@ -414,7 +409,7 @@ class TestCursor(IntegrationTest):
self.assertRaises(TypeError, db.test.find().limit, None)
self.assertRaises(TypeError, db.test.find().limit, "hello")
self.assertRaises(TypeError, db.test.find().limit, 5.5)
self.assertTrue(db.test.find().limit(long(5)))
self.assertTrue(db.test.find().limit(5))
db.test.drop()
db.test.insert_many([{"x": i} for i in range(100)])
@ -560,7 +555,7 @@ class TestCursor(IntegrationTest):
self.assertRaises(TypeError, db.test.find().batch_size, "hello")
self.assertRaises(TypeError, db.test.find().batch_size, 5.5)
self.assertRaises(ValueError, db.test.find().batch_size, -1)
self.assertTrue(db.test.find().batch_size(long(5)))
self.assertTrue(db.test.find().batch_size(5))
a = db.test.find()
for _ in a:
break
@ -684,7 +679,7 @@ class TestCursor(IntegrationTest):
self.assertRaises(TypeError, db.test.find().skip, "hello")
self.assertRaises(TypeError, db.test.find().skip, 5.5)
self.assertRaises(ValueError, db.test.find().skip, -5)
self.assertTrue(db.test.find().skip(long(5)))
self.assertTrue(db.test.find().skip(5))
db.drop_collection("test")
@ -1059,7 +1054,7 @@ class TestCursor(IntegrationTest):
self.assertEqual(5, len(list(self.db.test.find()[20:25])))
self.assertEqual(5, len(list(
self.db.test.find()[long(20):long(25)])))
self.db.test.find()[20:25])))
for a, b in zip(count(20), self.db.test.find()[20:25]):
self.assertEqual(a, b['i'])
@ -1104,7 +1099,7 @@ class TestCursor(IntegrationTest):
self.assertEqual(50, self.db.test.find()[50]['i'])
self.assertEqual(50, self.db.test.find().skip(50)[0]['i'])
self.assertEqual(50, self.db.test.find().skip(49)[1]['i'])
self.assertEqual(50, self.db.test.find()[long(50)]['i'])
self.assertEqual(50, self.db.test.find()[50]['i'])
self.assertEqual(99, self.db.test.find()[99]['i'])
self.assertRaises(IndexError, lambda x: self.db.test.find()[x], -1)

View File

@ -17,6 +17,7 @@
import datetime
import sys
import tempfile
from collections import OrderedDict
from decimal import Decimal
from random import random
@ -39,7 +40,6 @@ from bson.codec_options import (CodecOptions, TypeCodec, TypeDecoder,
from bson.errors import InvalidDocument
from bson.int64 import Int64
from bson.raw_bson import RawBSONDocument
from bson.py3compat import text_type
from gridfs import GridIn, GridOut
@ -110,7 +110,7 @@ UNINT_CODECOPTS = CodecOptions(type_registry=TypeRegistry(
class UppercaseTextDecoder(TypeDecoder):
bson_type = text_type
bson_type = str
def transform_bson(self, value):
return value.upper()

View File

@ -21,13 +21,11 @@ import warnings
sys.path[0:0] = [""]
from bson.code import Code
from bson.codec_options import CodecOptions
from bson.int64 import Int64
from bson.regex import Regex
from bson.dbref import DBRef
from bson.objectid import ObjectId
from bson.py3compat import string_type, text_type, PY3
from bson.son import SON
from pymongo import (ALL,
auth,
@ -63,10 +61,6 @@ from test.utils import (EventListener,
from test.test_custom_types import DECIMAL_CODECOPTS
if PY3:
long = int
class TestDatabaseNoConnect(unittest.TestCase):
"""Test Database features on a client that does not connect.
"""
@ -432,10 +426,10 @@ class TestDatabase(IntegrationTest):
# These basically clue us in to server changes.
self.assertTrue(isinstance(info[0]['responseLength'], int))
self.assertTrue(isinstance(info[0]['millis'], int))
self.assertTrue(isinstance(info[0]['client'], string_type))
self.assertTrue(isinstance(info[0]['user'], string_type))
self.assertTrue(isinstance(info[0]['ns'], string_type))
self.assertTrue(isinstance(info[0]['op'], string_type))
self.assertTrue(isinstance(info[0]['client'], str))
self.assertTrue(isinstance(info[0]['user'], str))
self.assertTrue(isinstance(info[0]['ns'], str))
self.assertTrue(isinstance(info[0]['op'], str))
self.assertTrue(isinstance(info[0]["ts"], datetime.datetime))
@client_context.require_no_mongos
@ -513,7 +507,7 @@ class TestDatabase(IntegrationTest):
self.assertRaises(TypeError, auth._password_digest, None)
self.assertTrue(isinstance(auth._password_digest("mike", "password"),
text_type))
str))
self.assertEqual(auth._password_digest("mike", "password"),
u"cd7e45b3b2767dc2fa9b6b548457ed00")
self.assertEqual(auth._password_digest("mike", "password"),
@ -828,7 +822,7 @@ class TestDatabase(IntegrationTest):
def test_long(self):
db = self.client.pymongo_test
db.test.drop()
db.test.insert_one({"x": long(9223372036854775807)})
db.test.insert_one({"x": 9223372036854775807})
retrieved = db.test.find_one()['x']
self.assertEqual(Int64(9223372036854775807), retrieved)
self.assertIsInstance(retrieved, Int64)

View File

@ -14,22 +14,14 @@
"""Tests for Decimal128."""
import codecs
import glob
import json
import os.path
import pickle
import sys
from binascii import unhexlify
from decimal import Decimal, DecimalException
from decimal import Decimal
sys.path[0:0] = [""]
from bson import BSON
from bson.decimal128 import Decimal128, create_decimal128_context
from bson.json_util import dumps, loads
from bson.py3compat import b
from test import client_context, unittest
class TestDecimal128(unittest.TestCase):

View File

@ -41,7 +41,6 @@ from test.utils import (assertion_context,
cdecimal_patched,
CMAPListener,
client_context,
Barrier,
get_pool,
HeartbeatEventListener,
server_name_to_type,
@ -263,7 +262,7 @@ class TestIgnoreStaleErrors(IntegrationTest):
def test_ignore_stale_connection_errors(self):
N_THREADS = 5
barrier = Barrier(N_THREADS, timeout=30)
barrier = threading.Barrier(N_THREADS, timeout=30)
client = rs_or_single_client(minPoolSize=N_THREADS)
self.addCleanup(client.close)

View File

@ -31,7 +31,6 @@ from bson.binary import (Binary,
STANDARD,
UUID_SUBTYPE)
from bson.codec_options import CodecOptions
from bson.py3compat import _unicode
from bson.errors import BSONError
from bson.json_util import JSONOptions
from bson.son import SON
@ -455,7 +454,7 @@ AZURE_CREDS = {
GCP_CREDS = {
'email': os.environ.get('FLE_GCP_EMAIL', ''),
'privateKey': _unicode(os.environ.get('FLE_GCP_PRIVATEKEY', ''))}
'privateKey': os.environ.get('FLE_GCP_PRIVATEKEY', '')}
class TestSpec(SpecRunner):
@ -1307,7 +1306,7 @@ class TestAzureEncryption(AzureGCPEncryptionTestMixin,
'AQGVERPgAAAAAAAAAAAAAAAC5DbBSwPwfSlBrDtRuglvNvCXD1KzDuCKY2P+4bRFtHDjpTOE2XuytPAUaAbXf1orsPq59PVZmsbTZbt2CB8qaQ==')
def test_automatic(self):
expected_document_extjson = textwrap.dedent("""
expected_document_extjson = textwrap.dedent("""
{"secret_azure": {
"$binary": {
"base64": "AQGVERPgAAAAAAAAAAAAAAAC5DbBSwPwfSlBrDtRuglvNvCXD1KzDuCKY2P+4bRFtHDjpTOE2XuytPAUaAbXf1orsPq59PVZmsbTZbt2CB8qaQ==",
@ -1333,7 +1332,7 @@ class TestGCPEncryption(AzureGCPEncryptionTestMixin,
'ARgj/gAAAAAAAAAAAAAAAAACwFd+Y5Ojw45GUXNvbcIpN9YkRdoHDHkR4kssdn0tIMKlDQOLFkWFY9X07IRlXsxPD8DcTiKnl6XINK28vhcGlg==')
def test_automatic(self):
expected_document_extjson = textwrap.dedent("""
expected_document_extjson = textwrap.dedent("""
{"secret_gcp": {
"$binary": {
"base64": "ARgj/gAAAAAAAAAAAAAAAAACwFd+Y5Ojw45GUXNvbcIpN9YkRdoHDHkR4kssdn0tIMKlDQOLFkWFY9X07IRlXsxPD8DcTiKnl6XINK28vhcGlg==",

View File

@ -45,10 +45,7 @@ class TestErrors(PyMongoTestCase):
self.assertIn("full error", traceback.format_exc())
def _test_unicode_strs(self, exc):
if sys.version_info[0] == 2:
self.assertEqual("unicode \xf0\x9f\x90\x8d, full error: {"
"'errmsg': u'unicode \\U0001f40d'}", str(exc))
elif 'PyPy' in sys.version:
if 'PyPy' in sys.version:
# PyPy displays unicode in repr differently.
self.assertEqual("unicode \U0001f40d, full error: {"
"'errmsg': 'unicode \\U0001f40d'}", str(exc))

View File

@ -20,10 +20,12 @@
import datetime
import sys
import zipfile
from io import BytesIO
sys.path[0:0] = [""]
from bson.objectid import ObjectId
from bson.py3compat import StringIO
from gridfs import GridFS
from gridfs.grid_file import (DEFAULT_CHUNK_SIZE,
_SEEK_CUR,
@ -234,7 +236,7 @@ class TestGridFile(IntegrationTest):
cursor = GridOutCursor(self.db.fs, {})
cursor_clone = cursor.clone()
cursor_dict = cursor.__dict__.copy()
cursor_dict.pop('_Cursor__session')
cursor_clone_dict = cursor_clone.__dict__.copy()
@ -301,7 +303,7 @@ class TestGridFile(IntegrationTest):
five = GridIn(self.db.fs, chunk_size=2)
five.write(b"hello")
buffer = StringIO(b" world")
buffer = BytesIO(b" world")
five.write(buffer)
five.write(b" and mongodb")
five.close()
@ -567,7 +569,7 @@ Bye"""))
def test_prechunked_string(self):
def write_me(s, chunk_size):
buf = StringIO(s)
buf = BytesIO(s)
infile = GridIn(self.db.fs)
while True:
to_write = buf.read(chunk_size)
@ -646,7 +648,7 @@ Bye"""))
self.assertIn("getMore", listener.started_command_names())
def test_zip(self):
zf = StringIO()
zf = BytesIO()
z = zipfile.ZipFile(zf, "w")
z.writestr("test.txt", b"hello world")
z.close()

View File

@ -16,21 +16,23 @@
"""Tests for the gridfs package.
"""
import sys
sys.path[0:0] = [""]
import datetime
import sys
import threading
import time
import gridfs
from io import BytesIO
sys.path[0:0] = [""]
from bson.binary import Binary
from bson.py3compat import StringIO, string_type
from pymongo.mongo_client import MongoClient
from pymongo.errors import (ConfigurationError,
NotMasterError,
ServerSelectionTimeoutError)
from pymongo.read_preferences import ReadPreference
import gridfs
from gridfs.errors import CorruptGridFile, FileExists, NoFile
from test import (client_context,
unittest,
@ -156,7 +158,7 @@ class TestGridfs(IntegrationTest):
self.assertEqual(oid, raw["_id"])
self.assertTrue(isinstance(raw["uploadDate"], datetime.datetime))
self.assertEqual(255 * 1024, raw["chunkSize"])
self.assertTrue(isinstance(raw["md5"], string_type))
self.assertTrue(isinstance(raw["md5"], str))
def test_corrupt_chunk(self):
files_id = self.fs.put(b'foobar')
@ -311,23 +313,38 @@ class TestGridfs(IntegrationTest):
time.sleep(0.01)
three = self.fs.put(b"baz", filename="test", author="author2")
self.assertEqual(b"foo", self.fs.get_version(filename="test", author="author1", version=-2).read())
self.assertEqual(b"bar", self.fs.get_version(filename="test", author="author1", version=-1).read())
self.assertEqual(b"foo", self.fs.get_version(filename="test", author="author1", version=0).read())
self.assertEqual(b"bar", self.fs.get_version(filename="test", author="author1", version=1).read())
self.assertEqual(b"baz", self.fs.get_version(filename="test", author="author2", version=0).read())
self.assertEqual(b"baz", self.fs.get_version(filename="test", version=-1).read())
self.assertEqual(b"baz", self.fs.get_version(filename="test", version=2).read())
self.assertEqual(
b"foo",
self.fs.get_version(
filename="test", author="author1", version=-2).read())
self.assertEqual(
b"bar", self.fs.get_version(
filename="test", author="author1", version=-1).read())
self.assertEqual(
b"foo", self.fs.get_version(
filename="test", author="author1", version=0).read())
self.assertEqual(
b"bar", self.fs.get_version(
filename="test", author="author1", version=1).read())
self.assertEqual(
b"baz", self.fs.get_version(
filename="test", author="author2", version=0).read())
self.assertEqual(
b"baz", self.fs.get_version(filename="test", version=-1).read())
self.assertEqual(
b"baz", self.fs.get_version(filename="test", version=2).read())
self.assertRaises(NoFile, self.fs.get_version, filename="test", author="author3")
self.assertRaises(NoFile, self.fs.get_version, filename="test", author="author1", version=2)
self.assertRaises(
NoFile, self.fs.get_version, filename="test", author="author3")
self.assertRaises(
NoFile, self.fs.get_version, filename="test", author="author1", version=2)
self.fs.delete(one)
self.fs.delete(two)
self.fs.delete(three)
def test_put_filelike(self):
oid = self.fs.put(StringIO(b"hello world"), chunk_size=1)
oid = self.fs.put(BytesIO(b"hello world"), chunk_size=1)
self.assertEqual(11, self.db.fs.chunks.count_documents({}))
self.assertEqual(b"hello world", self.fs.get(oid).read())

View File

@ -21,13 +21,13 @@ import itertools
import threading
import time
import gridfs
from io import BytesIO
from bson.binary import Binary
from bson.int64 import Int64
from bson.objectid import ObjectId
from bson.py3compat import StringIO, string_type
from bson.son import SON
import gridfs
from gridfs.errors import NoFile, CorruptGridFile
from pymongo.errors import (ConfigurationError,
NotMasterError,
@ -131,7 +131,7 @@ class TestGridfs(IntegrationTest):
self.assertEqual(oid, raw["_id"])
self.assertTrue(isinstance(raw["uploadDate"], datetime.datetime))
self.assertEqual(255 * 1024, raw["chunkSize"])
self.assertTrue(isinstance(raw["md5"], string_type))
self.assertTrue(isinstance(raw["md5"], str))
def test_corrupt_chunk(self):
files_id = self.fs.upload_from_stream("test_filename",
@ -293,7 +293,7 @@ class TestGridfs(IntegrationTest):
def test_upload_from_stream(self):
oid = self.fs.upload_from_stream("test_file",
StringIO(b"hello world"),
BytesIO(b"hello world"),
chunk_size_bytes=1)
self.assertEqual(11, self.db.fs.chunks.count_documents({}))
self.assertEqual(b"hello world",
@ -303,7 +303,7 @@ class TestGridfs(IntegrationTest):
oid = ObjectId()
self.fs.upload_from_stream_with_id(oid,
"test_file_custom_id",
StringIO(b"custom id"),
BytesIO(b"custom id"),
chunk_size_bytes=1)
self.assertEqual(b"custom id",
self.fs.open_download_stream(oid).read())
@ -416,11 +416,11 @@ class TestGridfs(IntegrationTest):
{"files_id": gin._id}))
def test_download_to_stream(self):
file1 = StringIO(b"hello world")
file1 = BytesIO(b"hello world")
# Test with one chunk.
oid = self.fs.upload_from_stream("one_chunk", file1)
self.assertEqual(1, self.db.fs.chunks.count_documents({}))
file2 = StringIO()
file2 = BytesIO()
self.fs.download_to_stream(oid, file2)
file1.seek(0)
file2.seek(0)
@ -434,18 +434,18 @@ class TestGridfs(IntegrationTest):
file1,
chunk_size_bytes=1)
self.assertEqual(11, self.db.fs.chunks.count_documents({}))
file2 = StringIO()
file2 = BytesIO()
self.fs.download_to_stream(oid, file2)
file1.seek(0)
file2.seek(0)
self.assertEqual(file1.read(), file2.read())
def test_download_to_stream_by_name(self):
file1 = StringIO(b"hello world")
file1 = BytesIO(b"hello world")
# Test with one chunk.
oid = self.fs.upload_from_stream("one_chunk", file1)
self.assertEqual(1, self.db.fs.chunks.count_documents({}))
file2 = StringIO()
file2 = BytesIO()
self.fs.download_to_stream_by_name("one_chunk", file2)
file1.seek(0)
file2.seek(0)
@ -458,7 +458,7 @@ class TestGridfs(IntegrationTest):
self.fs.upload_from_stream("many_chunks", file1, chunk_size_bytes=1)
self.assertEqual(11, self.db.fs.chunks.count_documents({}))
file2 = StringIO()
file2 = BytesIO()
self.fs.download_to_stream_by_name("many_chunks", file2)
file1.seek(0)
file2.seek(0)

View File

@ -13,22 +13,21 @@
# limitations under the License.
"""Test GridFSBucket class."""
import copy
import datetime
import os
import sys
import re
import sys
from json import loads
import gridfs
sys.path[0:0] = [""]
from bson import Binary
from bson.int64 import Int64
from bson.json_util import object_hook
from bson.py3compat import bytes_from_hex
import gridfs
from gridfs.errors import NoFile, CorruptGridFile
from test import (unittest,
IntegrationTest)
@ -210,7 +209,7 @@ def create_tests():
for key, val in jsn.items():
if key in ("data", "source", "result"):
if "$hex" in val:
jsn[key] = Binary(bytes_from_hex(val['$hex']))
jsn[key] = Binary(bytes.fromhex(val['$hex']))
if isinstance(jsn[key], dict):
str2hex(jsn[key])
if isinstance(jsn[key], list):

View File

@ -39,8 +39,6 @@ from bson.tz_util import FixedOffset, utc
from test import unittest, IntegrationTest
PY3 = sys.version_info[0] == 3
class TestJsonUtil(unittest.TestCase):
def round_tripped(self, doc, **kwargs):
@ -336,10 +334,7 @@ class TestJsonUtil(unittest.TestCase):
doc, json_util.loads(ext_json_str, json_options=options))
def test_binary(self):
if PY3:
bin_type_dict = {"bin": b"\x00\x01\x02\x03\x04"}
else:
bin_type_dict = {"bin": Binary(b"\x00\x01\x02\x03\x04")}
bin_type_dict = {"bin": b"\x00\x01\x02\x03\x04"}
md5_type_dict = {
"md5": Binary(b' n7\x18\xaf\t/\xd1\xd1/\x80\xca\xe7q\xcc\xac',
MD5_SUBTYPE)}
@ -352,10 +347,7 @@ class TestJsonUtil(unittest.TestCase):
# Binary with subtype 0 is decoded into bytes in Python 3.
bin = json_util.loads(
'{"bin": {"$binary": "AAECAwQ=", "$type": "00"}}')['bin']
if PY3:
self.assertEqual(type(bin), bytes)
else:
self.assertEqual(type(bin), Binary)
self.assertEqual(type(bin), bytes)
# PYTHON-443 ensure old type formats are supported
json_bin_dump = json_util.dumps(bin_type_dict)

View File

@ -19,7 +19,6 @@ import sys
import threading
import time
import uuid
import warnings
sys.path[0:0] = [""]
@ -27,14 +26,11 @@ from bson.binary import PYTHON_LEGACY, STANDARD
from bson.code import Code
from bson.codec_options import CodecOptions
from bson.objectid import ObjectId
from bson.py3compat import string_type
from bson.son import SON
from pymongo import ASCENDING, DESCENDING, GEOHAYSTACK
from pymongo.database import Database
from pymongo.common import partition_node
from pymongo.errors import (BulkWriteError,
ConfigurationError,
CursorNotFound,
DocumentTooLarge,
DuplicateKeyError,
InvalidDocument,
@ -42,7 +38,6 @@ from pymongo.errors import (BulkWriteError,
OperationFailure,
WriteConcernError,
WTimeoutError)
from pymongo.message import _CursorAddress
from pymongo.operations import IndexModel
from pymongo.son_manipulator import (AutoReference,
NamespaceInjector,
@ -143,14 +138,8 @@ class TestLegacy(IntegrationTest):
self.assertEqual(doc["_id"], _id)
self.assertTrue(isinstance(_id, ObjectId))
doc_class = dict
# Work around http://bugs.jython.org/issue1728
if (sys.platform.startswith('java') and
sys.version_info[:3] >= (2, 5, 2)):
doc_class = SON
db = self.client.get_database(
db.name, codec_options=CodecOptions(document_class=doc_class))
db.name, codec_options=CodecOptions(document_class=dict))
def remove_insert_find_one(doc):
db.test.remove({})
@ -2315,7 +2304,7 @@ class TestLegacyBulkWriteConcern(BulkTestBase):
failed = result['writeConcernErrors'][0]
self.assertEqual(64, failed['code'])
self.assertTrue(isinstance(failed['errmsg'], string_type))
self.assertTrue(isinstance(failed['errmsg'], str))
self.coll.delete_many({})
self.coll.create_index('a', unique=True)
@ -2413,12 +2402,12 @@ class TestLegacyBulkWriteConcern(BulkTestBase):
failed = result['writeErrors'][0]
self.assertEqual(2, failed['index'])
self.assertEqual(11000, failed['code'])
self.assertTrue(isinstance(failed['errmsg'], string_type))
self.assertTrue(isinstance(failed['errmsg'], str))
self.assertEqual(1, failed['op']['a'])
failed = result['writeConcernErrors'][0]
self.assertEqual(64, failed['code'])
self.assertTrue(isinstance(failed['errmsg'], string_type))
self.assertTrue(isinstance(failed['errmsg'], str))
upserts = result['upserted']
self.assertEqual(1, len(upserts))

View File

@ -21,7 +21,6 @@ import warnings
sys.path[0:0] = [""]
from bson.objectid import ObjectId
from bson.py3compat import text_type
from bson.son import SON
from pymongo import CursorType, monitoring, InsertOne, UpdateOne, DeleteOne
from pymongo.command_cursor import CommandCursor
@ -37,10 +36,8 @@ from test import (client_context,
unittest)
from test.utils import (EventListener,
get_pool,
ignore_deprecations,
rs_or_single_client,
single_client,
wait_until)
single_client)
class TestCommandMonitoring(PyMongoTestCase):
@ -821,7 +818,7 @@ class TestCommandMonitoring(PyMongoTestCase):
error = errors[0]
self.assertEqual(0, error.get('index'))
self.assertIsInstance(error.get('code'), int)
self.assertIsInstance(error.get('errmsg'), text_type)
self.assertIsInstance(error.get('errmsg'), str)
def test_legacy_writes(self):
with warnings.catch_warnings():

View File

@ -23,7 +23,6 @@ sys.path[0:0] = [""]
from bson.errors import InvalidId
from bson.objectid import ObjectId, _MAX_COUNTER_VALUE
from bson.py3compat import PY3, _unicode
from bson.tz_util import (FixedOffset,
utc)
from test import SkipTest, unittest
@ -50,7 +49,7 @@ class TestObjectId(unittest.TestCase):
def test_unicode(self):
a = ObjectId()
self.assertEqual(a, ObjectId(_unicode(a)))
self.assertEqual(a, ObjectId(a))
self.assertEqual(ObjectId("123456789012123456789012"),
ObjectId(u"123456789012123456789012"))
self.assertRaises(InvalidId, ObjectId, u"hello")
@ -139,13 +138,9 @@ class TestObjectId(unittest.TestCase):
b"object\np2\nNtp3\nRp4\n"
b"S'M\\x9afV\\x13v\\xc0\\x0b\\x88\\x00\\x00\\x00'\np5\nb.")
if PY3:
# Have to load using 'latin-1' since these were pickled in python2.x.
oid_1_9 = pickle.loads(pickled_with_1_9, encoding='latin-1')
oid_1_10 = pickle.loads(pickled_with_1_10, encoding='latin-1')
else:
oid_1_9 = pickle.loads(pickled_with_1_9)
oid_1_10 = pickle.loads(pickled_with_1_10)
# Have to load using 'latin-1' since these were pickled in python2.x.
oid_1_9 = pickle.loads(pickled_with_1_9, encoding='latin-1')
oid_1_10 = pickle.loads(pickled_with_1_10, encoding='latin-1')
self.assertEqual(oid_1_9, ObjectId("4d9a66561376c00b88000000"))
self.assertEqual(oid_1_9, oid_1_10)

View File

@ -23,7 +23,6 @@ import warnings
sys.path[0:0] = [""]
from bson.py3compat import MAXSIZE
from bson.son import SON
from pymongo.errors import ConfigurationError, OperationFailure
from pymongo.message import _maybe_add_read_preference
@ -430,7 +429,7 @@ class TestCommandAndReadPreference(IntegrationTest):
# the collection already exists.
self._test_primary_helper(
lambda: self.c.pymongo_test.create_collection(
'some_collection%s' % random.randint(0, MAXSIZE)))
'some_collection%s' % random.randint(0, sys.maxsize)))
@client_context.require_version_max(4, 1, 0, -1)
def test_group(self):

View File

@ -18,8 +18,9 @@ import copy
import os
import sys
from io import BytesIO
from bson import DBRef
from bson.py3compat import StringIO
from gridfs import GridFS, GridFSBucket
from pymongo import ASCENDING, InsertOne, IndexModel, OFF, monitoring
from pymongo.common import _MAX_END_SESSIONS
@ -465,7 +466,7 @@ class TestSession(IntegrationTest):
for f in files:
f.read()
sio = StringIO()
sio = BytesIO()
self._test_ops(
client,

View File

@ -21,9 +21,8 @@ import sys
sys.path[0:0] = [""]
from bson.py3compat import b
from bson.son import SON
from test import SkipTest, unittest
from test import unittest
class TestSON(unittest.TestCase):
@ -107,11 +106,10 @@ class TestSON(unittest.TestCase):
def test_pickle_backwards_compatability(self):
# This string was generated by pickling a SON object in pymongo
# version 2.1.1
pickled_with_2_1_1 = b(
pickled_with_2_1_1 = (
"ccopy_reg\n_reconstructor\np0\n(cbson.son\nSON\np1\n"
"c__builtin__\ndict\np2\n(dp3\ntp4\nRp5\n(dp6\n"
"S'_SON__keys'\np7\n(lp8\nsb."
)
"S'_SON__keys'\np7\n(lp8\nsb.").encode('utf8')
son_2_1_1 = pickle.loads(pickled_with_2_1_1)
self.assertEqual(son_2_1_1, SON([]))

View File

@ -450,9 +450,6 @@ class TestSSL(IntegrationTest):
if sys.platform == "win32":
raise SkipTest("Can't test system ca certs on Windows.")
if sys.version_info < (2, 7, 9):
raise SkipTest("Can't load system CA certificates.")
if (ssl.OPENSSL_VERSION.lower().startswith('libressl') and
sys.platform == 'darwin' and not _ssl.IS_PYOPENSSL):
raise SkipTest(

View File

@ -18,7 +18,6 @@ import sys
sys.path[0:0] = [""]
from bson.py3compat import imap
from pymongo import common
from pymongo.read_preferences import ReadPreference, Secondary
from pymongo.server_type import SERVER_TYPE
@ -52,7 +51,7 @@ def create_mock_topology(
seeds=None,
replica_set_name=None,
monitor_class=DummyMonitor):
partitioned_seeds = list(imap(common.partition_node, seeds or ['a']))
partitioned_seeds = list(map(common.partition_node, seeds or ['a']))
topology_settings = TopologySettings(
partitioned_seeds,
replica_set_name=replica_set_name,

View File

@ -17,9 +17,9 @@
import os
import sys
sys.path[0:0] = [""]
from io import BytesIO
from bson.py3compat import StringIO
sys.path[0:0] = [""]
from pymongo import client_session, WriteConcern
from pymongo.client_session import TransactionOptions
@ -270,8 +270,8 @@ class TestTransactions(TransactionsBase):
(gfs.exists, ()),
(gridfs_open_upload_stream, ('name',)),
(bucket.upload_from_stream, ('name', b'data',)),
(bucket.download_to_stream, (1, StringIO(),)),
(bucket.download_to_stream_by_name, ('name', StringIO(),)),
(bucket.download_to_stream, (1, BytesIO(),)),
(bucket.download_to_stream_by_name, ('name', BytesIO(),)),
(bucket.delete, (1,)),
(bucket.find, ()),
(bucket.open_download_stream, (1,)),

View File

@ -26,7 +26,6 @@ except ImportError:
sys.path[0:0] = [""]
from bson.binary import JAVA_LEGACY
from bson.py3compat import string_type, _unicode
from pymongo import ReadPreference
from pymongo.errors import ConfigurationError, InvalidURI
from pymongo.uri_parser import (parse_userinfo,
@ -169,7 +168,7 @@ class TestURI(unittest.TestCase):
split_options('connectTimeoutMS=0.1'))
self.assertTrue(split_options('connectTimeoutMS=300'))
self.assertTrue(isinstance(split_options('w=5')['w'], int))
self.assertTrue(isinstance(split_options('w=5.5')['w'], string_type))
self.assertTrue(isinstance(split_options('w=5.5')['w'], str))
self.assertTrue(split_options('w=foo'))
self.assertTrue(split_options('w=majority'))
self.assertTrue(split_options('wtimeoutms=500'))

View File

@ -4,7 +4,6 @@ sys.path[0:0] = [""]
from bson import encode
from bson.errors import InvalidStringData
from bson.py3compat import PY3
from test import unittest
class TestUTF8(unittest.TestCase):
@ -26,51 +25,5 @@ class TestUTF8(unittest.TestCase):
self.assertEqual(py_is_legal, bson_is_legal, data)
@unittest.skipIf(PY3, "python3 has strong separation between bytes/unicode")
def test_legal_utf8_full_coverage(self):
# This test takes 400 seconds. Which is too long to run each time.
# However it is the only one which covers all possible bit combinations
# in the 244 space.
b1 = chr(0xf4)
for b2 in map(chr, range(255)):
m2 = b1 + b2
self._assert_same_utf8_validation(m2)
for b3 in map(chr, range(255)):
m3 = m2 + b3
self._assert_same_utf8_validation(m3)
for b4 in map(chr, range(255)):
m4 = m3 + b4
self._assert_same_utf8_validation(m4)
# In python3:
# - 'bytes' are not checked with isLegalutf
# - 'unicode' We cannot create unicode objects with invalid utf8, since it
# would result in non valid code-points.
@unittest.skipIf(PY3, "python3 has strong separation between bytes/unicode")
def test_legal_utf8_few_samples(self):
good_samples = [
'\xf4\x80\x80\x80',
'\xf4\x8a\x80\x80',
'\xf4\x8e\x80\x80',
'\xf4\x81\x80\x80',
]
for data in good_samples:
self._assert_same_utf8_validation(data)
bad_samples = [
'\xf4\x00\x80\x80',
'\xf4\x3a\x80\x80',
'\xf4\x7f\x80\x80',
'\xf4\x90\x80\x80',
'\xf4\xff\x80\x80',
]
for data in bad_samples:
self._assert_same_utf8_validation(data)
if __name__ == "__main__":
unittest.main()

View File

@ -25,10 +25,11 @@ import re
import sys
import types
from collections import abc
from bson import json_util, Code, Decimal128, DBRef, SON, Int64, MaxKey, MinKey
from bson.binary import Binary
from bson.objectid import ObjectId
from bson.py3compat import abc, integer_types, iteritems, text_type, PY3
from bson.regex import Regex, RE_TYPE
from gridfs import GridFSBucket
@ -182,7 +183,7 @@ class EntityMapUtil(object):
item,))
def __setitem__(self, key, value):
if not isinstance(key, text_type):
if not isinstance(key, str):
self._test_class.fail(
'Expected entity name of type str, got %s' % (type(key)))
@ -197,7 +198,7 @@ class EntityMapUtil(object):
"Entity spec %s did not contain exactly one top-level key" % (
entity_spec,))
entity_type, spec = next(iteritems(entity_spec))
entity_type, spec = next(iter(entity_spec.items()))
if entity_type == 'client':
kwargs = {}
observe_events = spec.get('observeEvents', [])
@ -298,21 +299,16 @@ class EntityMapUtil(object):
return self._session_lsids[session_name]
if not PY3:
binary_types = (Binary,)
long_types = (Int64, long)
unicode_type = unicode
else:
binary_types = (Binary, bytes)
long_types = (Int64,)
unicode_type = str
binary_types = (Binary, bytes)
long_types = (Int64,)
unicode_type = str
BSON_TYPE_ALIAS_MAP = {
# https://docs.mongodb.com/manual/reference/operator/query/type/
# https://pymongo.readthedocs.io/en/stable/api/bson/index.html
'double': (float,),
'string': (text_type,),
'string': (str,),
'object': (abc.Mapping,),
'array': (abc.MutableSequence,),
'binData': binary_types,
@ -421,11 +417,11 @@ class MatchEvaluatorUtil(object):
else:
nested = expectation[key_to_compare]
if isinstance(nested, abc.Mapping) and len(nested) == 1:
opname, spec = next(iteritems(nested))
opname, spec = next(iter(nested.items()))
if opname.startswith('$$'):
is_special_op = True
elif len(expectation) == 1:
opname, spec = next(iteritems(expectation))
opname, spec = next(iter(expectation.items()))
if opname.startswith('$$'):
is_special_op = True
key_to_compare = None
@ -445,7 +441,7 @@ class MatchEvaluatorUtil(object):
return
self._test_class.assertIsInstance(actual, abc.Mapping)
for key, value in iteritems(expectation):
for key, value in expectation.items():
if self._evaluate_if_special_operation(expectation, actual, key):
continue
@ -473,7 +469,7 @@ class MatchEvaluatorUtil(object):
return
# account for flexible numerics in element-wise comparison
if (isinstance(expectation, integer_types) or
if (isinstance(expectation, int) or
isinstance(expectation, float)):
self._test_class.assertEqual(expectation, actual)
else:
@ -481,7 +477,7 @@ class MatchEvaluatorUtil(object):
self._test_class.assertEqual(expectation, actual)
def match_event(self, expectation, actual):
event_type, spec = next(iteritems(expectation))
event_type, spec = next(iter(expectation.items()))
# every event type has the commandName field
command_name = spec.get('commandName')

View File

@ -30,18 +30,16 @@ import warnings
from collections import defaultdict
from functools import partial
from bson import json_util, py3compat
from bson import json_util
from bson.objectid import ObjectId
from bson.py3compat import iteritems, string_type
from bson.son import SON
from pymongo import (MongoClient,
monitoring, operations, read_preferences)
from pymongo.collection import ReturnDocument
from pymongo.errors import ConfigurationError, OperationFailure
from pymongo.monitoring import _SENSITIVE_COMMANDS, ConnectionPoolListener
from pymongo.pool import (_CancellationContext,
PoolOptions)
from pymongo.monitoring import _SENSITIVE_COMMANDS
from pymongo.pool import _CancellationContext
from pymongo.read_concern import ReadConcern
from pymongo.read_preferences import ReadPreference
from pymongo.server_selectors import (any_server_selector,
@ -53,12 +51,6 @@ from test import (client_context,
db_user,
db_pwd)
if sys.version_info[0] < 3:
# Python 2.7, use our backport.
from test.barrier import Barrier
else:
from threading import Barrier
IMPOSSIBLE_WRITE_CONCERN = WriteConcern(w=50)
@ -289,7 +281,7 @@ class ScenarioDict(dict):
def convert(v):
if isinstance(v, collections.Mapping):
return ScenarioDict(v)
if isinstance(v, (py3compat.string_type, bytes)):
if isinstance(v, (str, bytes)):
return v
if isinstance(v, collections.Sequence):
return [convert(item) for item in v]
@ -974,7 +966,8 @@ def assertion_context(msg):
yield
except AssertionError as exc:
msg = '%s (%s)' % (exc, msg)
py3compat.reraise(type(exc), msg, sys.exc_info()[2])
exc_type, exc_val, exc_tb = sys.exc_info()
raise exc_type(exc_val).with_traceback(exc_tb)
def parse_spec_options(opts):
@ -998,8 +991,8 @@ def parse_spec_options(opts):
if 'hint' in opts:
hint = opts.pop('hint')
if not isinstance(hint, string_type):
hint = list(iteritems(hint))
if not isinstance(hint, str):
hint = list(hint.items())
opts['hint'] = hint
# Properly format 'hint' arguments for the Bulk API tests.
@ -1011,17 +1004,17 @@ def parse_spec_options(opts):
args = req.pop('arguments', {})
if 'hint' in args:
hint = args.pop('hint')
if not isinstance(hint, string_type):
hint = list(iteritems(hint))
if not isinstance(hint, str):
hint = list(hint.items())
args['hint'] = hint
req['arguments'] = args
else:
# Unified test format
bulk_model, spec = next(iteritems(req))
bulk_model, spec = next(iter(req.items()))
if 'hint' in spec:
hint = spec.pop('hint')
if not isinstance(hint, string_type):
hint = list(iteritems(hint))
if not isinstance(hint, str):
hint = list(hint.items())
spec['hint'] = hint
opts['requests'] = reqs
@ -1035,7 +1028,7 @@ def prepare_spec_arguments(spec, arguments, opname, entity_map,
# PyMongo accepts sort as list of tuples.
if arg_name == "sort":
sort_dict = arguments[arg_name]
arguments[arg_name] = list(iteritems(sort_dict))
arguments[arg_name] = list(sort_dict.items())
# Named "key" instead not fieldName.
if arg_name == "fieldName":
arguments["key"] = arguments.pop(arg_name)
@ -1057,7 +1050,7 @@ def prepare_spec_arguments(spec, arguments, opname, entity_map,
bulk_arguments = camel_to_snake_args(request["arguments"])
else:
# Unified test format
bulk_model, spec = next(iteritems(request))
bulk_model, spec = next(iter(request.items()))
bulk_class = getattr(operations, camel_to_upper_camel(bulk_model))
bulk_arguments = camel_to_snake_args(spec)
requests.append(bulk_class(**dict(bulk_arguments)))

View File

@ -14,23 +14,20 @@
"""Utilities for testing driver specs."""
import copy
import functools
import threading
from collections import abc
from bson import decode, encode
from bson.binary import Binary, STANDARD
from bson.codec_options import CodecOptions
from bson.int64 import Int64
from bson.py3compat import iteritems, abc, string_type, text_type
from bson.son import SON
from gridfs import GridFSBucket
from pymongo import (client_session,
helpers,
operations)
from pymongo import client_session
from pymongo.command_cursor import CommandCursor
from pymongo.cursor import Cursor
from pymongo.errors import (BulkWriteError,
@ -43,20 +40,16 @@ from pymongo.write_concern import WriteConcern
from test import (client_context,
client_knobs,
IntegrationTest,
unittest)
IntegrationTest)
from test.utils import (camel_to_snake,
camel_to_snake_args,
camel_to_upper_camel,
CompareType,
CMAPListener,
OvertCommandListener,
parse_spec_options,
parse_read_preference,
prepare_spec_arguments,
rs_client,
ServerAndTopologyEventListener,
HeartbeatEventListener)
ServerAndTopologyEventListener)
class SpecRunnerThread(threading.Thread):
@ -594,7 +587,7 @@ def expect_any_error(op):
def expect_error_message(expected_result):
if isinstance(expected_result, dict):
return isinstance(expected_result['errorContains'], text_type)
return isinstance(expected_result['errorContains'], str)
return False