PYTHON-800 - Add CodecOptions class.

This commit is contained in:
Bernie Hackett 2014-12-12 14:11:44 -08:00
parent 8a64f261fd
commit b87fb790a2
6 changed files with 116 additions and 23 deletions

View File

@ -14,8 +14,10 @@
"""Tools to parse mongo client options."""
from bson.binary import OLD_UUID_SUBTYPE
from bson.py3compat import iteritems
from pymongo.auth import _build_credentials_tuple
from pymongo.codec_options import CodecOptions
from pymongo.common import validate
from pymongo.errors import ConfigurationError
from pymongo.pool import PoolOptions
@ -34,6 +36,14 @@ def _parse_credentials(username, password, database, options):
mechanism, source, username, password, options)
def _parse_codec_options(options):
"""Parse BSON codec options."""
as_class = options.get('document_class', dict)
tz_aware = options.get('tz_aware', False)
uuid_rep = options.get('uuidrepresentation', OLD_UUID_SUBTYPE)
return CodecOptions(as_class, tz_aware, uuid_rep)
def _parse_read_preference(options):
"""Parse read preference options."""
if 'read_preference' in options:
@ -113,21 +123,20 @@ class ClientOptions(object):
self.__credentials = _parse_credentials(
username, password, database, options)
self.__codec_options = _parse_codec_options(options)
self.__pool_options = _parse_pool_options(options)
self.__read_preference = _parse_read_preference(options)
self.__replica_set_name = options.get('replicaset')
self.__write_concern = _parse_write_concern(options)
# TODO: BSONOptions
self.__uuid_subtype = options.get('uuidrepresentation')
@property
def credentials(self):
"""A MongoCredentials instance or None."""
"""A :class:`~pymongo.auth.MongoCredentials` instance or None."""
return self.__credentials
@property
def pool_options(self):
"""A PoolOptions instance."""
"""A :class:`~pymongo.pool.PoolOptions` instance."""
return self.__pool_options
@property
@ -141,11 +150,11 @@ class ClientOptions(object):
return self.__replica_set_name
@property
def uuid_subtype(self):
"""BSON UUID representation."""
return self.__uuid_subtype
def codec_options(self):
"""A :class:`~pymongo.codec_options.CodecOptions` instance."""
return self.__codec_options
@property
def write_concern(self):
"""A WriteConcern instance."""
"""A :class:`~pymongo.write_concern.WriteConcern` instance."""
return self.__write_concern

66
pymongo/codec_options.py Normal file
View File

@ -0,0 +1,66 @@
# Copyright 2014 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.
"""Tools for specifying BSON codec options."""
from collections import MutableMapping
from bson.binary import OLD_UUID_SUBTYPE
class CodecOptions(object):
"""Encapsulates BSON options used in CRUD operations.
:Parameters:
- `as_class`: BSON documents returned in queries will be decoded
to an instance of this class. Must be a subclass of
:class:`~collections.MutableMapping`. Defaults to :class:`dict`.
- `tz_aware`: If ``True``, BSON datetimes will be decoded to timezone
aware instances of :class:`~datetime.datetime`. Otherwise they will be
naive. Defaults to ``False``.
- `uuid_representation`: The BSON representation to use when encoding
and decoding instances of :class:`~uuid.UUID`. Defaults to
:data:`~bson.binary.OLD_UUID_SUBTYPE`.
"""
__slots__ = ("__as_class", "__tz_aware", "__uuid_rep")
def __init__(self, as_class=dict,
tz_aware=False, uuid_representation=OLD_UUID_SUBTYPE):
if not issubclass(as_class, MutableMapping):
raise TypeError("document_class must be a "
"subclass of MutableMapping")
if not isinstance(tz_aware, bool):
raise TypeError("tz_aware must be a boolean")
if not isinstance(uuid_representation, int):
raise TypeError("uuid_representation must be an integer")
self.__as_class = as_class
self.__tz_aware = tz_aware
self.__uuid_rep = uuid_representation
@property
def as_class(self):
"""Read only property for as_class."""
return self.__as_class
@property
def tz_aware(self):
"""Read only property for tz_aware."""
return self.__tz_aware
@property
def uuid_representation(self):
"""Read only property for uuid_subtype."""
return self.__uuid_rep

View File

@ -98,8 +98,8 @@ class Collection(common.BaseObject):
.. mongodoc:: collections
"""
super(Collection, self).__init__(database.read_preference,
database.uuid_subtype,
super(Collection, self).__init__(database.codec_options,
database.read_preference,
database.write_concern)
if not isinstance(name, string_type):

View File

@ -19,6 +19,7 @@ import collections
import warnings
from pymongo.auth import MECHANISMS
from pymongo.codec_options import CodecOptions
from pymongo.errors import ConfigurationError
from pymongo.read_preferences import (make_read_preference,
read_pref_mode_from_name,
@ -302,6 +303,13 @@ def validate_auth_mechanism_properties(option, value):
return props
def validate_document_class(option, value):
if not issubclass(value, collections.MutableMapping):
raise ConfigurationError("%s must be a sublass of "
"collections.MutableMapping" % (option,))
return value
# journal is an alias for j,
# wtimeoutms is an alias for wtimeout,
VALIDATORS = {
@ -331,6 +339,8 @@ VALIDATORS = {
'authmechanism': validate_auth_mechanism,
'authsource': validate_string,
'authmechanismproperties': validate_auth_mechanism_properties,
'document_class': validate_document_class,
'tz_aware': validate_boolean,
'uuidrepresentation': validate_uuid_representation,
}
@ -374,12 +384,17 @@ class BaseObject(object):
SHOULD NOT BE USED BY DEVELOPERS EXTERNAL TO MONGODB.
"""
def __init__(self, read_preference, uuid_subtype, write_concern):
def __init__(self, codec_options, read_preference, write_concern):
self.__codec_options = codec_options
self.__read_pref = read_preference
self.__uuid_subtype = uuid_subtype or OLD_UUID_SUBTYPE
self.__write_concern = WriteConcern(**write_concern)
@property
def codec_options(self):
"""An instance of :class:`~pymongo.codec_options.CodecOptions`."""
return self.__codec_options
def __set_write_concern(self, value):
"""Property setter for write_concern."""
if not isinstance(value, collections.Mapping):
@ -498,11 +513,14 @@ class BaseObject(object):
subtype 4. It can also be used to force legacy byte order and subtype
compatibility with the Java and C# drivers. See the :mod:`bson.binary`
module for all options."""
return self.__uuid_subtype
return self.__codec_options.uuid_representation
def __set_uuid_subtype(self, value):
"""Sets the BSON Binary subtype to be used when storing UUIDs."""
self.__uuid_subtype = validate_uuid_subtype("uuid_subtype", value)
uuid_representation = validate_uuid_subtype("uuid_subtype", value)
self.__codec_options = CodecOptions(self.__codec_options.as_class,
self.__codec_options.tz_aware,
uuid_representation)
uuid_subtype = property(__get_uuid_subtype, __set_uuid_subtype)

View File

@ -76,8 +76,8 @@ class Database(common.BaseObject):
db.__my_collection__
"""
super(Database, self).__init__(connection.read_preference,
connection.uuid_subtype,
super(Database, self).__init__(connection.codec_options,
connection.read_preference,
connection.write_concern)
if not isinstance(name, string_type):

View File

@ -282,20 +282,20 @@ class MongoClient(common.BaseObject):
condition_class = kwargs.pop('_condition_class', None)
kwargs['max_pool_size'] = max_pool_size
kwargs['document_class'] = document_class
kwargs['tz_aware'] = tz_aware
opts.update(kwargs)
self.__options = options = ClientOptions(
username, password, dbase, opts)
self.__default_database_name = dbase
self.__cursor_manager = CursorManager(self)
self.__document_class = document_class
self.__tz_aware = common.validate_boolean('tz_aware', tz_aware)
# Cache of existing indexes used by ensure_index ops.
self.__index_cache = {}
super(MongoClient, self).__init__(options.read_preference,
options.uuid_subtype,
super(MongoClient, self).__init__(options.codec_options,
options.read_preference,
options.write_concern.document)
self.__all_credentials = {}
@ -521,7 +521,7 @@ class MongoClient(common.BaseObject):
.. versionchanged:: 3.0
Now read-only.
"""
return self.__document_class
return self.__options.codec_options.as_class
def get_document_class(self):
"""Default class to use for documents returned from this client.
@ -532,13 +532,13 @@ class MongoClient(common.BaseObject):
' document_class property',
DeprecationWarning, stacklevel=2)
return self.__document_class
return self.__options.codec_options.as_class
@property
def tz_aware(self):
"""Does this client return timezone-aware datetimes?
"""
return self.__tz_aware
return self.__options.codec_options.tz_aware
@property
def max_bson_size(self):