rename from_dict,to_dict to encode,decode, respectively

This commit is contained in:
Mike Dirolf 2010-09-13 10:49:43 -04:00
parent 9c182809f3
commit 6880e4af60
4 changed files with 126 additions and 100 deletions

View File

@ -15,10 +15,11 @@
"""BSON (Binary JSON) encoding and decoding.
"""
import struct
import re
import datetime
import calendar
import datetime
import re
import struct
import warnings
from bson.binary import Binary
from bson.code import Code
@ -420,35 +421,65 @@ class BSON(str):
@classmethod
def from_dict(cls, dct, check_keys=False):
"""Create a new :class:`BSON` instance from a mapping type
(like :class:`dict`).
"""DEPRECATED - `from_dict` has been renamed to `encode`.
Raises :class:`TypeError` if `dct` is not a mapping type, or
contains keys that are not instances of :class:`basestring`.
Raises :class:`~bson.errors.InvalidDocument` if `dct` cannot
be converted to :class:`BSON`.
.. versionchanged:: 1.8.1+
Deprecated in favor of :meth:`encode`
"""
warnings.warn("`from_dict` has been renamed to `encode`",
DeprecationWarning)
return cls.encode(dct, check_keys)
@classmethod
def encode(cls, document, check_keys=False):
"""Encode a document to a new :class:`BSON` instance.
A document can be any mapping type (like :class:`dict`).
Raises :class:`TypeError` if `document` is not a mapping type,
or contains keys that are not instances of
:class:`basestring`. Raises
:class:`~bson.errors.InvalidDocument` if `document` cannot be
converted to :class:`BSON`.
:Parameters:
- `dct`: mapping type representing a document
- `document`: mapping type representing a document
- `check_keys` (optional): check if keys start with '$' or
contain '.', raising :class:`~bson.errors.InvalidName` in
either case
.. versionadded:: 1.8.1+
"""
return cls(_dict_to_bson(dct, check_keys))
return cls(_dict_to_bson(document, check_keys))
def to_dict(self, as_class=dict, tz_aware=False):
"""Convert this BSON data to a mapping type.
"""DEPRECATED - `to_dict` has been renamed to `decode`.
The default type to use is :class:`dict`. This can be replaced
using the `as_class` parameter.
.. versionchanged:: 1.8.1+
Deprecated in favor of :meth:`decode`
.. versionadded:: 1.8
The `tz_aware` parameter.
.. versionadded:: 1.7
The `as_class` parameter.
"""
warnings.warn("`to_dict` has been renamed to `decode`",
DeprecationWarning)
return self.decode(as_class, tz_aware)
If `tz_aware` is ``True`` (default), any
def decode(self, as_class=dict, tz_aware=False):
"""Decode this BSON data.
The default type to use for the resultant document is
:class:`dict`. Any other class that supports
:meth:`__setitem__` can be used instead by passing it as the
`as_class` parameter.
If `tz_aware` is ``True`` (recommended), any
:class:`~datetime.datetime` instances returned will be
timezone-aware, with their timezone set to
:attr:`bson.tz_util.utc`. Otherwise, all
:attr:`bson.tz_util.utc`. Otherwise (default), all
:class:`~datetime.datetime` instances will be naive (but
contain UTC) - this was the default behavior in PyMongo
versions **<= 1.7**.
contain UTC).
:Parameters:
- `as_class` (optional): the class to use for the resulting
@ -456,10 +487,7 @@ class BSON(str):
- `tz_aware` (optional): if ``True``, return timezone-aware
:class:`~datetime.datetime` instances
.. versionadded:: 1.8
The `tz_aware` parameter.
.. versionadded:: 1.7
The `as_class` parameter.
.. versionadded:: 1.8.1+
"""
(document, _) = _bson_to_dict(self, as_class, tz_aware)
return document

View File

@ -93,7 +93,7 @@ def _unpack_response(response, cursor_id=None, as_class=dict, tz_aware=False):
raise OperationFailure("cursor id '%s' not valid at server" %
cursor_id)
elif response_flag & 2:
error_object = bson.BSON(response[20:]).to_dict()
error_object = bson.BSON(response[20:]).decode()
if error_object["$err"] == "not master":
raise AutoReconnect("master has changed")
raise OperationFailure("database error: %s" %

View File

@ -64,8 +64,7 @@ def insert(collection_name, docs, check_keys, safe, last_error_args):
"""
data = __ZERO
data += bson._make_c_string(collection_name)
bson_data = "".join([bson.BSON.from_dict(doc, check_keys)
for doc in docs])
bson_data = "".join([bson.BSON.encode(doc, check_keys) for doc in docs])
if not bson_data:
raise InvalidOperation("cannot do an empty bulk insert")
data += bson_data
@ -91,8 +90,8 @@ def update(collection_name, upsert, multi, spec, doc, safe, last_error_args):
data = __ZERO
data += bson._make_c_string(collection_name)
data += struct.pack("<i", options)
data += bson.BSON.from_dict(spec)
data += bson.BSON.from_dict(doc)
data += bson.BSON.encode(spec)
data += bson.BSON.encode(doc)
if safe:
(_, update_message) = __pack_message(2001, data)
(request_id, error_message) = __last_error(last_error_args)
@ -111,9 +110,9 @@ def query(options, collection_name,
data += bson._make_c_string(collection_name)
data += struct.pack("<i", num_to_skip)
data += struct.pack("<i", num_to_return)
data += bson.BSON.from_dict(query)
data += bson.BSON.encode(query)
if field_selector is not None:
data += bson.BSON.from_dict(field_selector)
data += bson.BSON.encode(field_selector)
return __pack_message(2004, data)
if _use_c:
query = _cbson._query_message
@ -137,7 +136,7 @@ def delete(collection_name, spec, safe, last_error_args):
data = __ZERO
data += bson._make_c_string(collection_name)
data += __ZERO
data += bson.BSON.from_dict(spec)
data += bson.BSON.encode(spec)
if safe:
(_, remove_message) = __pack_message(2006, data)
(request_id, error_message) = __last_error(last_error_args)

View File

@ -69,11 +69,11 @@ class TestBSON(unittest.TestCase):
qcheck.check_unittest(self, qcheck.isnt(is_valid),
qcheck.gen_string(qcheck.gen_range(0, 40)))
def test_basic_to_dict(self):
def test_basic_decode(self):
self.assertEqual({"test": u"hello world"},
BSON("\x1B\x00\x00\x00\x0E\x74\x65\x73\x74\x00\x0C"
"\x00\x00\x00\x68\x65\x6C\x6C\x6F\x20\x77\x6F"
"\x72\x6C\x64\x00\x00").to_dict())
"\x72\x6C\x64\x00\x00").decode())
self.assertEqual([{"test": u"hello world"}, {}],
_to_dicts("\x1B\x00\x00\x00\x0E\x74\x65\x73\x74\x00"
"\x0C\x00\x00\x00\x68\x65\x6C\x6C\x6F\x20"
@ -83,77 +83,76 @@ class TestBSON(unittest.TestCase):
def test_data_timestamp(self):
self.assertEqual({"test": Timestamp(4, 20)},
BSON("\x13\x00\x00\x00\x11\x74\x65\x73\x74\x00\x14"
"\x00\x00\x00\x04\x00\x00\x00\x00").to_dict())
"\x00\x00\x00\x04\x00\x00\x00\x00").decode())
def test_basic_from_dict(self):
self.assertRaises(TypeError, BSON.from_dict, 100)
self.assertRaises(TypeError, BSON.from_dict, "hello")
self.assertRaises(TypeError, BSON.from_dict, None)
self.assertRaises(TypeError, BSON.from_dict, [])
def test_basic_encode(self):
self.assertRaises(TypeError, BSON.encode, 100)
self.assertRaises(TypeError, BSON.encode, "hello")
self.assertRaises(TypeError, BSON.encode, None)
self.assertRaises(TypeError, BSON.encode, [])
self.assertEqual(BSON.from_dict({}), BSON("\x05\x00\x00\x00\x00"))
self.assertEqual(BSON.from_dict({"test": u"hello world"}),
self.assertEqual(BSON.encode({}), BSON("\x05\x00\x00\x00\x00"))
self.assertEqual(BSON.encode({"test": u"hello world"}),
"\x1B\x00\x00\x00\x02\x74\x65\x73\x74\x00\x0C\x00\x00"
"\x00\x68\x65\x6C\x6C\x6F\x20\x77\x6F\x72\x6C\x64\x00"
"\x00")
self.assertEqual(BSON.from_dict({u"mike": 100}),
self.assertEqual(BSON.encode({u"mike": 100}),
"\x0F\x00\x00\x00\x10\x6D\x69\x6B\x65\x00\x64\x00\x00"
"\x00\x00")
self.assertEqual(BSON.from_dict({"hello": 1.5}),
self.assertEqual(BSON.encode({"hello": 1.5}),
"\x14\x00\x00\x00\x01\x68\x65\x6C\x6C\x6F\x00\x00\x00"
"\x00\x00\x00\x00\xF8\x3F\x00")
self.assertEqual(BSON.from_dict({"true": True}),
self.assertEqual(BSON.encode({"true": True}),
"\x0C\x00\x00\x00\x08\x74\x72\x75\x65\x00\x01\x00")
self.assertEqual(BSON.from_dict({"false": False}),
self.assertEqual(BSON.encode({"false": False}),
"\x0D\x00\x00\x00\x08\x66\x61\x6C\x73\x65\x00\x00"
"\x00")
self.assertEqual(BSON.from_dict({"empty": []}),
self.assertEqual(BSON.encode({"empty": []}),
"\x11\x00\x00\x00\x04\x65\x6D\x70\x74\x79\x00\x05\x00"
"\x00\x00\x00\x00")
self.assertEqual(BSON.from_dict({"none": {}}),
self.assertEqual(BSON.encode({"none": {}}),
"\x10\x00\x00\x00\x03\x6E\x6F\x6E\x65\x00\x05\x00\x00"
"\x00\x00\x00")
self.assertEqual(BSON.from_dict({"test": Binary("test", 0)}),
self.assertEqual(BSON.encode({"test": Binary("test", 0)}),
"\x14\x00\x00\x00\x05\x74\x65\x73\x74\x00\x04\x00\x00"
"\x00\x00\x74\x65\x73\x74\x00")
self.assertEqual(BSON.from_dict({"test": Binary("test")}),
self.assertEqual(BSON.encode({"test": Binary("test")}),
"\x18\x00\x00\x00\x05\x74\x65\x73\x74\x00\x08\x00\x00"
"\x00\x02\x04\x00\x00\x00\x74\x65\x73\x74\x00")
self.assertEqual(BSON.from_dict({"test": Binary("test", 128)}),
self.assertEqual(BSON.encode({"test": Binary("test", 128)}),
"\x14\x00\x00\x00\x05\x74\x65\x73\x74\x00\x04\x00\x00"
"\x00\x80\x74\x65\x73\x74\x00")
self.assertEqual(BSON.from_dict({"test": None}),
self.assertEqual(BSON.encode({"test": None}),
"\x0B\x00\x00\x00\x0A\x74\x65\x73\x74\x00\x00")
self.assertEqual(BSON.from_dict({"date": datetime.datetime(2007, 1, 8,
0, 30,
11)}),
self.assertEqual(BSON.encode({"date": datetime.datetime(2007, 1, 8,
0, 30, 11)}),
"\x13\x00\x00\x00\x09\x64\x61\x74\x65\x00\x38\xBE\x1C"
"\xFF\x0F\x01\x00\x00\x00")
self.assertEqual(BSON.from_dict({"regex": re.compile("a*b",
re.IGNORECASE)}),
self.assertEqual(BSON.encode({"regex": re.compile("a*b",
re.IGNORECASE)}),
"\x12\x00\x00\x00\x0B\x72\x65\x67\x65\x78\x00\x61\x2A"
"\x62\x00\x69\x00\x00")
self.assertEqual(BSON.from_dict({"$where": Code("test")}),
self.assertEqual(BSON.encode({"$where": Code("test")}),
"\x1F\x00\x00\x00\x0F\x24\x77\x68\x65\x72\x65\x00\x12"
"\x00\x00\x00\x05\x00\x00\x00\x74\x65\x73\x74\x00\x05"
"\x00\x00\x00\x00\x00")
a = ObjectId("\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0A\x0B")
self.assertEqual(BSON.from_dict({"oid": a}),
self.assertEqual(BSON.encode({"oid": a}),
"\x16\x00\x00\x00\x07\x6F\x69\x64\x00\x00\x01\x02\x03"
"\x04\x05\x06\x07\x08\x09\x0A\x0B\x00")
self.assertEqual(BSON.from_dict({"ref": DBRef("coll", a)}),
self.assertEqual(BSON.encode({"ref": DBRef("coll", a)}),
"\x2F\x00\x00\x00\x03ref\x00\x25\x00\x00\x00\x02$ref"
"\x00\x05\x00\x00\x00coll\x00\x07$id\x00\x00\x01\x02"
"\x03\x04\x05\x06\x07\x08\x09\x0A\x0B\x00\x00")
def test_from_then_to_dict(self):
def test_encode_then_decode(self):
def helper(dict):
self.assertEqual(dict, (BSON.from_dict(dict)).to_dict())
self.assertEqual(dict, (BSON.encode(dict)).decode())
helper({})
helper({"test": u"hello"})
self.assert_(isinstance(BSON.from_dict({"hello": "world"})
.to_dict()["hello"],
self.assert_(isinstance(BSON.encode({"hello": "world"})
.decode()["hello"],
unicode))
helper({"mike": -10120})
helper({"long": long(10)})
@ -177,17 +176,17 @@ class TestBSON(unittest.TestCase):
helper({"foo": MinKey()})
helper({"foo": MaxKey()})
def from_then_to_dict(dict):
return dict == (BSON.from_dict(dict)).to_dict()
def encode_then_decode(dict):
return dict == (BSON.encode(dict)).decode()
qcheck.check_unittest(self, from_then_to_dict,
qcheck.check_unittest(self, encode_then_decode,
qcheck.gen_mongo_dict(3))
def test_aware_datetime(self):
aware = datetime.datetime(1993, 4, 4, 2, tzinfo=FixedOffset(555, "SomeZone"))
as_utc = (aware - aware.utcoffset()).replace(tzinfo=utc)
self.assertEqual(datetime.datetime(1993, 4, 3, 16, 45, tzinfo=utc), as_utc)
after = BSON.from_dict({"date": aware}).to_dict(tz_aware=True)["date"]
after = BSON.encode({"date": aware}).decode(tz_aware=True)["date"]
self.assertEqual(utc, after.tzinfo)
self.assertEqual(as_utc, after)
@ -195,35 +194,35 @@ class TestBSON(unittest.TestCase):
aware = datetime.datetime(1993, 4, 4, 2, tzinfo=FixedOffset(555, "SomeZone"))
naive_utc = (aware - aware.utcoffset()).replace(tzinfo=None)
self.assertEqual(datetime.datetime(1993, 4, 3, 16, 45), naive_utc)
after = BSON.from_dict({"date": aware}).to_dict()["date"]
after = BSON.encode({"date": aware}).decode()["date"]
self.assertEqual(None, after.tzinfo)
self.assertEqual(naive_utc, after)
def test_dst(self):
d = {"x": datetime.datetime(1993, 4, 4, 2)}
self.assertEqual(d, BSON.from_dict(d).to_dict())
self.assertEqual(d, BSON.encode(d).decode())
def test_bad_encode(self):
self.assertRaises(InvalidStringData, BSON.from_dict,
self.assertRaises(InvalidStringData, BSON.encode,
{"lalala": '\xf4\xe0\xf0\xe1\xc0 Color Touch'})
def test_overflow(self):
self.assert_(BSON.from_dict({"x": 9223372036854775807L}))
self.assertRaises(OverflowError, BSON.from_dict, {"x": 9223372036854775808L})
self.assert_(BSON.encode({"x": 9223372036854775807L}))
self.assertRaises(OverflowError, BSON.encode, {"x": 9223372036854775808L})
self.assert_(BSON.from_dict({"x": -9223372036854775808L}))
self.assertRaises(OverflowError, BSON.from_dict, {"x": -9223372036854775809L})
self.assert_(BSON.encode({"x": -9223372036854775808L}))
self.assertRaises(OverflowError, BSON.encode, {"x": -9223372036854775809L})
def test_tuple(self):
self.assertEqual({"tuple": [1, 2]},
BSON.from_dict({"tuple": (1, 2)}).to_dict())
BSON.encode({"tuple": (1, 2)}).decode())
def test_uuid(self):
if not should_test_uuid:
raise SkipTest()
id = uuid.uuid4()
transformed_id = (BSON.from_dict({"id": id})).to_dict()["id"]
transformed_id = (BSON.encode({"id": id})).decode()["id"]
self.assert_(isinstance(transformed_id, uuid.UUID))
self.assertEqual(id, transformed_id)
@ -233,58 +232,58 @@ class TestBSON(unittest.TestCase):
# that doesn't really test anything but the lack of a segfault.
def test_unicode_regex(self):
regex = re.compile(u'revisi\xf3n')
BSON.from_dict({"regex": regex}).to_dict()
BSON.encode({"regex": regex}).decode()
def test_non_string_keys(self):
self.assertRaises(InvalidDocument, BSON.from_dict, {8.9: "test"})
self.assertRaises(InvalidDocument, BSON.encode, {8.9: "test"})
def test_large_document(self):
self.assertRaises(InvalidDocument, BSON.from_dict, {"key": "x"*4*1024*1024})
self.assertRaises(InvalidDocument, BSON.encode, {"key": "x"*4*1024*1024})
def test_utf8(self):
w = {u"aéあ": u"aéあ"}
self.assertEqual(w, BSON.from_dict(w).to_dict())
self.assertEqual(w, BSON.encode(w).decode())
x = {u"aéあ".encode("utf-8"): u"aéあ".encode("utf-8")}
self.assertEqual(w, BSON.from_dict(x).to_dict())
self.assertEqual(w, BSON.encode(x).decode())
y = {"hello": u"".encode("iso-8859-1")}
self.assertRaises(InvalidStringData, BSON.from_dict, y)
self.assertRaises(InvalidStringData, BSON.encode, y)
z = {u"".encode("iso-8859-1"): "hello"}
self.assertRaises(InvalidStringData, BSON.from_dict, z)
self.assertRaises(InvalidStringData, BSON.encode, z)
def test_null_character(self):
doc = {"a": "\x00"}
self.assertEqual(doc, BSON.from_dict(doc).to_dict())
self.assertEqual(doc, BSON.encode(doc).decode())
doc = {"a": u"\x00"}
self.assertEqual(doc, BSON.from_dict(doc).to_dict())
self.assertEqual(doc, BSON.encode(doc).decode())
self.assertRaises(InvalidDocument, BSON.from_dict, {"\x00": "a"})
self.assertRaises(InvalidDocument, BSON.from_dict, {u"\x00": "a"})
self.assertRaises(InvalidDocument, BSON.encode, {"\x00": "a"})
self.assertRaises(InvalidDocument, BSON.encode, {u"\x00": "a"})
self.assertRaises(InvalidDocument, BSON.from_dict, {"a": re.compile("ab\x00c")})
self.assertRaises(InvalidDocument, BSON.from_dict, {"a": re.compile(u"ab\x00c")})
self.assertRaises(InvalidDocument, BSON.encode, {"a": re.compile("ab\x00c")})
self.assertRaises(InvalidDocument, BSON.encode, {"a": re.compile(u"ab\x00c")})
def test_move_id(self):
self.assertEqual("\x19\x00\x00\x00\x02_id\x00\x02\x00\x00\x00a\x00"
"\x02a\x00\x02\x00\x00\x00a\x00\x00",
BSON.from_dict(SON([("a", "a"), ("_id", "a")])))
BSON.encode(SON([("a", "a"), ("_id", "a")])))
self.assertEqual("\x2c\x00\x00\x00"
"\x02_id\x00\x02\x00\x00\x00b\x00"
"\x03b\x00"
"\x19\x00\x00\x00\x02a\x00\x02\x00\x00\x00a\x00"
"\x02_id\x00\x02\x00\x00\x00a\x00\x00\x00",
BSON.from_dict(SON([("b", SON([("a", "a"), ("_id", "a")])),
("_id", "b")])))
BSON.encode(SON([("b", SON([("a", "a"), ("_id", "a")])),
("_id", "b")])))
def test_dates(self):
doc = {"early": datetime.datetime(1686, 5, 5),
"late": datetime.datetime(2086, 5, 5)}
try:
self.assertEqual(doc, BSON.from_dict(doc).to_dict())
self.assertEqual(doc, BSON.encode(doc).decode())
except ValueError:
# Ignore ValueError when no C ext, since it's probably
# a problem w/ 32-bit Python - we work around this in the
@ -293,14 +292,14 @@ class TestBSON(unittest.TestCase):
raise
def test_custom_class(self):
self.assert_(isinstance(BSON.from_dict({}).to_dict(), dict))
self.assertFalse(isinstance(BSON.from_dict({}).to_dict(), SON))
self.assert_(isinstance(BSON.from_dict({}).to_dict(SON), SON))
self.assert_(isinstance(BSON.encode({}).decode(), dict))
self.assertFalse(isinstance(BSON.encode({}).decode(), SON))
self.assert_(isinstance(BSON.encode({}).decode(SON), SON))
self.assertEqual(1, BSON.from_dict({"x": 1}).to_dict(SON)["x"])
self.assertEqual(1, BSON.encode({"x": 1}).decode(SON)["x"])
x = BSON.from_dict({"x": [{"y": 1}]})
self.assert_(isinstance(x.to_dict(SON)["x"][0], SON))
x = BSON.encode({"x": [{"y": 1}]})
self.assert_(isinstance(x.decode(SON)["x"][0], SON))
def test_subclasses(self):
# make sure we can serialize subclasses of native Python types.
@ -313,7 +312,7 @@ class TestBSON(unittest.TestCase):
d = {'a' : _myint(42), 'b' : _myfloat(63.9),
'c' : _myunicode('hello world')
}
d2 = BSON.from_dict(d).to_dict()
d2 = BSON.encode(d).decode()
for key, value in d2.iteritems():
orig_value = d[key]
orig_type = orig_value.__class__.__bases__[0]
@ -326,7 +325,7 @@ class TestBSON(unittest.TestCase):
except ImportError:
raise SkipTest()
d = OrderedDict([("one", 1), ("two", 2), ("three", 3), ("four", 4)])
self.assertEqual(d, BSON.from_dict(d).to_dict(as_class=OrderedDict))
self.assertEqual(d, BSON.encode(d).decode(as_class=OrderedDict))
if __name__ == "__main__":