Created
March 8, 2011 19:59
-
-
Save alts/860908 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, long)): | |
# TODO this is a really ugly way to check for this... | |
if value > 2 ** 64 / 2 - 1 or value < -2 ** 64 / 2: | |
raise OverflowError("BSON can only handle up to 8-byte ints") | |
if value > 2 ** 32 / 2 - 1 or value < -2 ** 32 / 2: | |
return "\x12" + name + struct.pack("<q", value) | |
return "\x10" + name + struct.pack("<i", 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)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment