From d4a94d30fd15bc39b9282ba0c98705f370f33d6b Mon Sep 17 00:00:00 2001 From: Luke Lovett Date: Thu, 17 Apr 2014 21:29:15 +0000 Subject: [PATCH] PYTHON-673 python 2/3 single-source for the bson module --- bson/__init__.py | 85 +++++++++++++++++++++++++---------------------- bson/code.py | 6 ++-- bson/dbref.py | 11 +++--- bson/json_util.py | 10 +++--- bson/objectid.py | 9 +++-- bson/py3compat.py | 39 +++++++++++++++++----- bson/regex.py | 6 ++-- bson/son.py | 9 +++-- bson/timestamp.py | 5 +-- 9 files changed, 107 insertions(+), 73 deletions(-) diff --git a/bson/__init__.py b/bson/__init__.py index adafadbf4..15045c38b 100644 --- a/bson/__init__.py +++ b/bson/__init__.py @@ -31,7 +31,13 @@ from bson.errors import (InvalidBSON, from bson.max_key import MaxKey from bson.min_key import MinKey from bson.objectid import ObjectId -from bson.py3compat import b, binary_type +from bson.py3compat import (b, + PY3, + binary_type, + iteritems, + text_type, + string_type, + reraise) from bson.regex import Regex from bson.son import SON, RE_TYPE from bson.timestamp import Timestamp @@ -50,8 +56,8 @@ try: except ImportError: _use_uuid = False -PY3 = sys.version_info[0] == 3 - +if PY3: + long = int MAX_INT32 = 2147483647 MIN_INT32 = -2147483648 @@ -61,33 +67,30 @@ MIN_INT64 = -9223372036854775808 EPOCH_AWARE = datetime.datetime.fromtimestamp(0, utc) EPOCH_NAIVE = datetime.datetime.utcfromtimestamp(0) -# Create constants compatible with all versions of -# python from 2.4 forward. In 2.x b("foo") is just -# "foo". In 3.x it becomes b"foo". -EMPTY = b("") -ZERO = b("\x00") -ONE = b("\x01") +EMPTY = b"" +ZERO = b"\x00" +ONE = b"\x01" -BSONNUM = b("\x01") # Floating point -BSONSTR = b("\x02") # UTF-8 string -BSONOBJ = b("\x03") # Embedded document -BSONARR = b("\x04") # Array -BSONBIN = b("\x05") # Binary -BSONUND = b("\x06") # Undefined -BSONOID = b("\x07") # ObjectId -BSONBOO = b("\x08") # Boolean -BSONDAT = b("\x09") # UTC Datetime -BSONNUL = b("\x0A") # Null -BSONRGX = b("\x0B") # Regex -BSONREF = b("\x0C") # DBRef -BSONCOD = b("\x0D") # Javascript code -BSONSYM = b("\x0E") # Symbol -BSONCWS = b("\x0F") # Javascript code with scope -BSONINT = b("\x10") # 32bit int -BSONTIM = b("\x11") # Timestamp -BSONLON = b("\x12") # 64bit int -BSONMIN = b("\xFF") # Min key -BSONMAX = b("\x7F") # Max key +BSONNUM = b"\x01" # Floating point +BSONSTR = b"\x02" # UTF-8 string +BSONOBJ = b"\x03" # Embedded document +BSONARR = b"\x04" # Array +BSONBIN = b"\x05" # Binary +BSONUND = b"\x06" # Undefined +BSONOID = b"\x07" # ObjectId +BSONBOO = b"\x08" # Boolean +BSONDAT = b"\x09" # UTC Datetime +BSONNUL = b"\x0A" # Null +BSONRGX = b"\x0B" # Regex +BSONREF = b"\x0C" # DBRef +BSONCOD = b"\x0D" # Javascript code +BSONSYM = b"\x0E" # Symbol +BSONCWS = b"\x0F" # Javascript code with scope +BSONINT = b"\x10" # 32bit int +BSONTIM = b"\x11" # Timestamp +BSONLON = b"\x12" # 64bit int +BSONMIN = b"\xFF" # Min key +BSONMAX = b"\x7F" # Max key def _get_int(data, position, as_class=None, @@ -117,12 +120,7 @@ def _get_c_string(data, position, length=None): def _make_c_string(string, check_null=False): - if isinstance(string, unicode): - if check_null and "\x00" in string: - raise InvalidDocument("BSON keys / regex patterns must not " - "contain a NULL character") - return string.encode("utf-8") + ZERO - else: + if isinstance(string, bytes): if check_null and ZERO in string: raise InvalidDocument("BSON keys / regex patterns must not " "contain a NULL character") @@ -132,6 +130,11 @@ def _make_c_string(string, check_null=False): except UnicodeError: raise InvalidStringData("strings in documents must be valid " "UTF-8: %r" % string) + else: + if check_null and "\x00" in string: + raise InvalidDocument("BSON keys / regex patterns must not " + "contain a NULL character") + return string.encode("utf-8") + ZERO def _get_number(data, position, as_class, tz_aware, uuid_subtype, compile_re): @@ -349,7 +352,7 @@ if _use_c: def _element_to_bson(key, value, check_keys, uuid_subtype): - if not isinstance(key, basestring): + if not isinstance(key, string_type): raise InvalidDocument("documents must have only string keys, " "key was %r" % key) @@ -405,7 +408,7 @@ def _element_to_bson(key, value, check_keys, uuid_subtype): cstring = _make_c_string(value) length = struct.pack(" MAX_INT64 or value < MIN_INT64: raise OverflowError("BSON can only handle up to 8-byte ints") return BSONLON + name + struct.pack("