def _element_to_bson(key, value, check_keys, uuid_subtype): if not isinstance(key, basestring): raise InvalidDocument("documents must have only string keys, " "key was %r" % key) if check_keys: if key.startswith("$"): raise InvalidDocument("key %r must not start with '$'" % key) if "." in key: raise InvalidDocument("key %r must not contain '.'" % key) name = _make_c_string(key, True) if isinstance(value, float): return BSONNUM + name + struct.pack("<d", value) if _use_uuid: if isinstance(value, uuid.UUID): # Java Legacy if uuid_subtype == JAVA_LEGACY: # Python 3.0(.1) returns a bytearray instance for bytes (3.1 # and newer just return a bytes instance). Convert that to # binary_type (here and below) for compatibility. from_uuid = binary_type(value.bytes) as_legacy_java = from_uuid[0:8][::-1] + from_uuid[8:16][::-1] value = Binary(as_legacy_java, subtype=OLD_UUID_SUBTYPE) # C# legacy elif uuid_subtype == CSHARP_LEGACY: # Microsoft GUID representation. value = Binary(binary_type(value.bytes_le), subtype=OLD_UUID_SUBTYPE) # Python else: value = Binary(binary_type(value.bytes), subtype=uuid_subtype) if isinstance(value, Binary): subtype = value.subtype if subtype == 2: value = struct.pack("<i", len(value)) + value return (BSONBIN + name + struct.pack("<i", len(value)) + b(chr(subtype)) + value) if isinstance(value, Code): cstring = _make_c_string(value) if not value.scope: length = struct.pack("<i", len(cstring)) return BSONCOD + name + length + cstring scope = _dict_to_bson(value.scope, False, uuid_subtype, False) full_length = struct.pack("<i", 8 + len(cstring) + len(scope)) length = struct.pack("<i", len(cstring)) return BSONCWS + name + full_length + length + cstring + scope if isinstance(value, binary_type): if PY3: # Python3 special case. Store 'bytes' as BSON binary subtype 0. return (BSONBIN + name + struct.pack("<i", len(value)) + ZERO + value) cstring = _make_c_string(value) length = struct.pack("<i", len(cstring)) return BSONSTR + name + length + cstring if isinstance(value, unicode): cstring = _make_c_string(value) length = struct.pack("<i", len(cstring)) return BSONSTR + name + length + cstring if isinstance(value, dict): return BSONOBJ + name + _dict_to_bson(value, check_keys, uuid_subtype, False) if isinstance(value, (list, tuple)): as_dict = SON(zip([str(i) for i in range(len(value))], value)) return BSONARR + name + _dict_to_bson(as_dict, check_keys, uuid_subtype, False) if isinstance(value, ObjectId): return BSONOID + name + value.binary if value is True: return BSONBOO + name + ONE if value is False: return BSONBOO + name + ZERO if isinstance(value, int): # TODO this is an ugly way to check for this... if value > MAX_INT64 or value < MIN_INT64: raise OverflowError("BSON can only handle up to 8-byte ints") if value > MAX_INT32 or value < MIN_INT32: return BSONLON + name + struct.pack("<q", value) return BSONINT + name + struct.pack("<i", value) # 2to3 will convert long to int here since there is no long in python3. # That's OK. The previous if block will match instead. if isinstance(value, long): if value > MAX_INT64 or value < MIN_INT64: raise OverflowError("BSON can only handle up to 8-byte ints") return BSONLON + name + struct.pack("<q", value) if isinstance(value, datetime.datetime): if value.utcoffset() is not None: value = value - value.utcoffset() millis = int(calendar.timegm(value.timetuple()) * 1000 + value.microsecond / 1000) return BSONDAT + name + struct.pack("<q", millis) if isinstance(value, Timestamp): time = struct.pack("<I", value.time) inc = struct.pack("<I", value.inc) return BSONTIM + name + inc + time if value is None: return BSONNUL + name if isinstance(value, (RE_TYPE, Regex)): pattern = value.pattern flags = "" if value.flags & re.IGNORECASE: flags += "i" if value.flags & re.LOCALE: flags += "l" if value.flags & re.MULTILINE: flags += "m" if value.flags & re.DOTALL: flags += "s" if value.flags & re.UNICODE: flags += "u" if value.flags & re.VERBOSE: flags += "x" return BSONRGX + name + _make_c_string(pattern, True) + \ _make_c_string(flags) if isinstance(value, DBRef): return _element_to_bson(key, value.as_doc(), False, uuid_subtype) if isinstance(value, MinKey): return BSONMIN + name if isinstance(value, MaxKey): return BSONMAX + name raise InvalidDocument("cannot convert value of type %s to bson" % type(value))
def _element_to_bson(key, value, check_keys, uuid_subtype): if not isinstance(key, str_type): raise InvalidDocument("documents must have only string keys, " "key was %r" % key) if check_keys: if key.startswith("$"): raise InvalidDocument("key %r must not start with '$'" % key) if "." in key: raise InvalidDocument("key %r must not contain '.'" % key) name = _make_c_string(key, True) if isinstance(value, float): return BSONNUM + name + struct.pack("d", value) if _use_uuid: if isinstance(value, uuid.UUID): # Java Legacy if uuid_subtype == JAVA_LEGACY: # Python 3.0(.1) returns a bytearray instance for bytes (3.1 # and newer just return a bytes instance). Convert that to # binary_type (here and below) for compatibility. from_uuid = binary_type(value.bytes) as_legacy_java = from_uuid[0:8][::-1] + from_uuid[8:16][::-1] value = Binary(as_legacy_java, subtype=OLD_UUID_SUBTYPE) # C# legacy elif uuid_subtype == CSHARP_LEGACY: # Microsoft GUID representation. value = Binary(binary_type(value.bytes_le), subtype=OLD_UUID_SUBTYPE) # Python else: value = Binary(binary_type(value.bytes), subtype=uuid_subtype) if isinstance(value, Binary): subtype = value.subtype if subtype == 2: value = struct.pack("i", len(value)) + value return (BSONBIN + name + struct.pack("i", len(value)) + b(chr(subtype)) + value) if isinstance(value, Code): cstring = _make_c_string(value) if not value.scope: length = struct.pack("i", len(cstring)) return BSONCOD + name + length + cstring scope = _dict_to_bson(value.scope, False, uuid_subtype, False) full_length = struct.pack("i", 8 + len(cstring) + len(scope)) length = struct.pack("i", len(cstring)) return BSONCWS + name + full_length + length + cstring + scope if isinstance(value, binary_type): if PY3: # Python3 special case. Store 'bytes' as BSON binary subtype 0. return (BSONBIN + name + struct.pack("i", len(value)) + ZERO + value) cstring = _make_c_string(value) length = struct.pack("i", len(cstring)) return BSONSTR + name + length + cstring if isinstance(value, text_type): cstring = _make_c_string(value) length = struct.pack("i", len(cstring)) return BSONSTR + name + length + cstring if isinstance(value, dict): return BSONOBJ + name + _dict_to_bson(value, check_keys, uuid_subtype, False) if isinstance(value, (list, tuple)): as_dict = SON(zip([str(i) for i in range(len(value))], value)) return BSONARR + name + _dict_to_bson(as_dict, check_keys, uuid_subtype, False) if isinstance(value, ObjectId): return BSONOID + name + value.binary if value is True: return BSONBOO + name + ONE if value is False: return BSONBOO + name + ZERO if isinstance(value, int): # TODO this is an ugly way to check for this... if value > MAX_INT64 or value < MIN_INT64: raise OverflowError("BSON can only handle up to 8-byte ints") if value > MAX_INT32 or value < MIN_INT32: return BSONLON + name + struct.pack("q", value) return BSONINT + name + struct.pack("i", value) # 2to3 will convert long to int here since there is no long in python3. # That's OK. The previous if block will match instead. if isinstance(value, long_type): if value > MAX_INT64 or value < MIN_INT64: raise OverflowError("BSON can only handle up to 8-byte ints") return BSONLON + name + struct.pack("q", value) if isinstance(value, datetime.datetime): if value.utcoffset() is not None: value = value - value.utcoffset() millis = int(calendar.timegm(value.timetuple()) * 1000 + value.microsecond / 1000) return BSONDAT + name + struct.pack("q", millis) if isinstance(value, Timestamp): time = struct.pack("i", value.time) inc = struct.pack("i", value.inc) return BSONTIM + name + inc + time if value is None: return BSONNUL + name if isinstance(value, (RE_TYPE, Regex)): pattern = value.pattern flags = "" if value.flags & re.IGNORECASE: flags += "i" if value.flags & re.LOCALE: flags += "l" if value.flags & re.MULTILINE: flags += "m" if value.flags & re.DOTALL: flags += "s" if value.flags & re.UNICODE: flags += "u" if value.flags & re.VERBOSE: flags += "x" return BSONRGX + name + _make_c_string(pattern, True) + \ _make_c_string(flags) if isinstance(value, DBRef): return _element_to_bson(key, value.as_doc(), False, uuid_subtype) if isinstance(value, MinKey): return BSONMIN + name if isinstance(value, MaxKey): return BSONMAX + name if isinstance(value, Decimal): return BSONDECIMAL + name + value._to_bson_element_value() # struct.pack(fmt, a) #value.to_bson_element_value() raise InvalidDocument("cannot convert value of type %s to bson" % type(value))
def _element_to_bson(key, value, check_keys, uuid_subtype): if not isinstance(key, basestring): raise InvalidDocument("documents must have only string keys, " "key was %r" % key) if check_keys: if key.startswith("$"): raise InvalidDocument("key %r must not start with '$'" % key) if "." in key: raise InvalidDocument("key %r must not contain '.'" % key) name = _make_c_string(key, True) if isinstance(value, float): return "\x01" + name + struct.pack("<d", value) # Use Binary w/ subtype 3 for UUID instances if _use_uuid: if isinstance(value, uuid.UUID): value = Binary(value.bytes, subtype=uuid_subtype) if isinstance(value, Binary): subtype = value.subtype if subtype == 2: value = struct.pack("<i", len(value)) + value return "\x05%s%s%s%s" % (name, struct.pack("<i", len(value)), chr(subtype), value) if isinstance(value, Code): cstring = _make_c_string(value) if not value.scope: length = struct.pack("<i", len(cstring)) return "\x0D" + name + length + cstring scope = _dict_to_bson(value.scope, False, uuid_subtype, False) full_length = struct.pack("<i", 8 + len(cstring) + len(scope)) length = struct.pack("<i", len(cstring)) return "\x0F" + name + full_length + length + cstring + scope if isinstance(value, str): cstring = _make_c_string(value) length = struct.pack("<i", len(cstring)) return "\x02" + name + length + cstring if isinstance(value, unicode): cstring = _make_c_string(value) length = struct.pack("<i", len(cstring)) return "\x02" + name + length + cstring if isinstance(value, dict): return "\x03" + name + _dict_to_bson(value, check_keys, uuid_subtype, False) if isinstance(value, (list, tuple)): as_dict = SON(zip([str(i) for i in range(len(value))], value)) return "\x04" + name + _dict_to_bson(as_dict, check_keys, uuid_subtype, False) if isinstance(value, ObjectId): return "\x07" + name + value.binary if value is True: return "\x08" + name + "\x01" if value is False: return "\x08" + name + "\x00" if isinstance(value, int): # TODO this is an ugly way to check for this... if value > MAX_INT64 or value < MIN_INT64: raise OverflowError("BSON can only handle up to 8-byte ints") if value > MAX_INT32 or value < MIN_INT32: return "\x12" + name + struct.pack("<q", value) return "\x10" + name + struct.pack("<i", value) if isinstance(value, long): # XXX No long type in Python 3 if value > MAX_INT64 or value < MIN_INT64: raise OverflowError("BSON can only handle up to 8-byte ints") return "\x12" + name + struct.pack("<q", value) if isinstance(value, datetime.datetime): if value.utcoffset() is not None: value = value - value.utcoffset() millis = int(calendar.timegm(value.timetuple()) * 1000 + value.microsecond / 1000) return "\x09" + name + struct.pack("<q", millis) if isinstance(value, Timestamp): time = struct.pack("<I", value.time) inc = struct.pack("<I", value.inc) return "\x11" + name + inc + time if value is None: return "\x0A" + name if isinstance(value, RE_TYPE): pattern = value.pattern flags = "" if value.flags & re.IGNORECASE: flags += "i" if value.flags & re.LOCALE: flags += "l" if value.flags & re.MULTILINE: flags += "m" if value.flags & re.DOTALL: flags += "s" if value.flags & re.UNICODE: flags += "u" if value.flags & re.VERBOSE: flags += "x" return "\x0B" + name + _make_c_string(pattern, True) + \ _make_c_string(flags) if isinstance(value, DBRef): return _element_to_bson(key, value.as_doc(), False, uuid_subtype) if isinstance(value, MinKey): return "\xFF" + name if isinstance(value, MaxKey): return "\x7F" + name raise InvalidDocument("cannot convert value of type %s to bson" % type(value))
def _element_to_bson(key, value, check_keys): if not isinstance(key, basestring): raise InvalidDocument("documents must have only string keys, " "key was %r" % key) if check_keys: if key.startswith("$"): raise InvalidDocument("key %r must not start with '$'" % key) if "." in key: raise InvalidDocument("key %r must not contain '.'" % key) name = _make_c_string(key, True) if isinstance(value, float): return "\x01" + name + struct.pack("<d", value) # Use Binary w/ subtype 3 for UUID instances try: import uuid if isinstance(value, uuid.UUID): value = Binary(value.bytes, subtype=3) except ImportError: pass if isinstance(value, Binary): subtype = value.subtype if subtype == 2: value = struct.pack("<i", len(value)) + value return "\x05%s%s%s%s" % (name, struct.pack( "<i", len(value)), chr(subtype), value) if isinstance(value, Code): cstring = _make_c_string(value) scope = _dict_to_bson(value.scope, False, False) full_length = struct.pack("<i", 8 + len(cstring) + len(scope)) length = struct.pack("<i", len(cstring)) return "\x0F" + name + full_length + length + cstring + scope if isinstance(value, str): cstring = _make_c_string(value) length = struct.pack("<i", len(cstring)) return "\x02" + name + length + cstring if isinstance(value, unicode): cstring = _make_c_string(value) length = struct.pack("<i", len(cstring)) return "\x02" + name + length + cstring if isinstance(value, dict): return "\x03" + name + _dict_to_bson(value, check_keys, False) if isinstance(value, (list, tuple)): as_dict = SON(zip([str(i) for i in range(len(value))], value)) return "\x04" + name + _dict_to_bson(as_dict, check_keys, False) if isinstance(value, ObjectId): return "\x07" + name + value.binary if value is True: return "\x08" + name + "\x01" if value is False: return "\x08" + name + "\x00" if isinstance(value, int): # TODO this is an ugly way to check for this... if value > MAX_INT64 or value < MIN_INT64: raise OverflowError("BSON can only handle up to 8-byte ints") if value > MAX_INT32 or value < MIN_INT32: return "\x12" + name + struct.pack("<q", value) return "\x10" + name + struct.pack("<i", value) if isinstance(value, long): # XXX No long type in Python 3 if value > MAX_INT64 or value < MIN_INT64: raise OverflowError("BSON can only handle up to 8-byte ints") return "\x12" + name + struct.pack("<q", value) if isinstance(value, datetime.datetime): if value.utcoffset() is not None: value = value - value.utcoffset() millis = int( calendar.timegm(value.timetuple()) * 1000 + value.microsecond / 1000) return "\x09" + name + struct.pack("<q", millis) if isinstance(value, Timestamp): time = struct.pack("<I", value.time) inc = struct.pack("<I", value.inc) return "\x11" + name + inc + time if value is None: return "\x0A" + name if isinstance(value, RE_TYPE): pattern = value.pattern flags = "" if value.flags & re.IGNORECASE: flags += "i" if value.flags & re.LOCALE: flags += "l" if value.flags & re.MULTILINE: flags += "m" if value.flags & re.DOTALL: flags += "s" if value.flags & re.UNICODE: flags += "u" if value.flags & re.VERBOSE: flags += "x" return "\x0B" + name + _make_c_string(pattern, True) + \ _make_c_string(flags) if isinstance(value, DBRef): return _element_to_bson(key, value.as_doc(), False) if isinstance(value, MinKey): return "\xFF" + name if isinstance(value, MaxKey): return "\x7F" + name raise InvalidDocument("cannot convert value of type %s to bson" % type(value))