xtquant.xtbson.bson36.codec_options
Tools for specifying BSON codec options.
1# Copyright 2014-present MongoDB, Inc. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Tools for specifying BSON codec options.""" 16 17import abc 18import datetime 19import warnings 20from collections import namedtuple 21from collections.abc import MutableMapping as _MutableMapping 22 23from .binary import ( 24 ALL_UUID_REPRESENTATIONS, 25 UUID_REPRESENTATION_NAMES, 26 UuidRepresentation, 27) 28 29 30def _abstractproperty(func): 31 return property(abc.abstractmethod(func)) 32 33 34_RAW_BSON_DOCUMENT_MARKER = 101 35 36 37def _raw_document_class(document_class): 38 """Determine if a document_class is a RawBSONDocument class.""" 39 marker = getattr(document_class, "_type_marker", None) 40 return marker == _RAW_BSON_DOCUMENT_MARKER 41 42 43class TypeEncoder(abc.ABC): 44 """Base class for defining type codec classes which describe how a 45 custom type can be transformed to one of the types BSON understands. 46 47 Codec classes must implement the ``python_type`` attribute, and the 48 ``transform_python`` method to support encoding. 49 50 See :ref:`custom-type-type-codec` documentation for an example. 51 """ 52 53 @_abstractproperty 54 def python_type(self): 55 """The Python type to be converted into something serializable.""" 56 pass 57 58 @abc.abstractmethod 59 def transform_python(self, value): 60 """Convert the given Python object into something serializable.""" 61 pass 62 63 64class TypeDecoder(abc.ABC): 65 """Base class for defining type codec classes which describe how a 66 BSON type can be transformed to a custom type. 67 68 Codec classes must implement the ``bson_type`` attribute, and the 69 ``transform_bson`` method to support decoding. 70 71 See :ref:`custom-type-type-codec` documentation for an example. 72 """ 73 74 @_abstractproperty 75 def bson_type(self): 76 """The BSON type to be converted into our own type.""" 77 pass 78 79 @abc.abstractmethod 80 def transform_bson(self, value): 81 """Convert the given BSON value into our own type.""" 82 pass 83 84 85class TypeCodec(TypeEncoder, TypeDecoder): 86 """Base class for defining type codec classes which describe how a 87 custom type can be transformed to/from one of the types :mod:`bson` 88 can already encode/decode. 89 90 Codec classes must implement the ``python_type`` attribute, and the 91 ``transform_python`` method to support encoding, as well as the 92 ``bson_type`` attribute, and the ``transform_bson`` method to support 93 decoding. 94 95 See :ref:`custom-type-type-codec` documentation for an example. 96 """ 97 98 pass 99 100 101class TypeRegistry(object): 102 """Encapsulates type codecs used in encoding and / or decoding BSON, as 103 well as the fallback encoder. Type registries cannot be modified after 104 instantiation. 105 106 ``TypeRegistry`` can be initialized with an iterable of type codecs, and 107 a callable for the fallback encoder:: 108 109 >>> from .codec_options import TypeRegistry 110 >>> type_registry = TypeRegistry([Codec1, Codec2, Codec3, ...], 111 ... fallback_encoder) 112 113 See :ref:`custom-type-type-registry` documentation for an example. 114 115 :Parameters: 116 - `type_codecs` (optional): iterable of type codec instances. If 117 ``type_codecs`` contains multiple codecs that transform a single 118 python or BSON type, the transformation specified by the type codec 119 occurring last prevails. A TypeError will be raised if one or more 120 type codecs modify the encoding behavior of a built-in :mod:`bson` 121 type. 122 - `fallback_encoder` (optional): callable that accepts a single, 123 unencodable python value and transforms it into a type that 124 :mod:`bson` can encode. See :ref:`fallback-encoder-callable` 125 documentation for an example. 126 """ 127 128 def __init__(self, type_codecs=None, fallback_encoder=None): 129 self.__type_codecs = list(type_codecs or []) 130 self._fallback_encoder = fallback_encoder 131 self._encoder_map = {} 132 self._decoder_map = {} 133 134 if self._fallback_encoder is not None: 135 if not callable(fallback_encoder): 136 raise TypeError("fallback_encoder %r is not a callable" % (fallback_encoder)) 137 138 for codec in self.__type_codecs: 139 is_valid_codec = False 140 if isinstance(codec, TypeEncoder): 141 self._validate_type_encoder(codec) 142 is_valid_codec = True 143 self._encoder_map[codec.python_type] = codec.transform_python 144 if isinstance(codec, TypeDecoder): 145 is_valid_codec = True 146 self._decoder_map[codec.bson_type] = codec.transform_bson 147 if not is_valid_codec: 148 raise TypeError( 149 "Expected an instance of %s, %s, or %s, got %r instead" 150 % (TypeEncoder.__name__, TypeDecoder.__name__, TypeCodec.__name__, codec) 151 ) 152 153 def _validate_type_encoder(self, codec): 154 from . import _BUILT_IN_TYPES 155 156 for pytype in _BUILT_IN_TYPES: 157 if issubclass(codec.python_type, pytype): 158 err_msg = ( 159 "TypeEncoders cannot change how built-in types are " 160 "encoded (encoder %s transforms type %s)" % (codec, pytype) 161 ) 162 raise TypeError(err_msg) 163 164 def __repr__(self): 165 return "%s(type_codecs=%r, fallback_encoder=%r)" % ( 166 self.__class__.__name__, 167 self.__type_codecs, 168 self._fallback_encoder, 169 ) 170 171 def __eq__(self, other): 172 if not isinstance(other, type(self)): 173 return NotImplemented 174 return ( 175 (self._decoder_map == other._decoder_map) 176 and (self._encoder_map == other._encoder_map) 177 and (self._fallback_encoder == other._fallback_encoder) 178 ) 179 180 181_options_base = namedtuple( 182 "CodecOptions", 183 ( 184 "document_class", 185 "tz_aware", 186 "uuid_representation", 187 "unicode_decode_error_handler", 188 "tzinfo", 189 "type_registry", 190 ), 191) 192 193 194class CodecOptions(_options_base): 195 """Encapsulates options used encoding and / or decoding BSON. 196 197 The `document_class` option is used to define a custom type for use 198 decoding BSON documents. Access to the underlying raw BSON bytes for 199 a document is available using the :class:`~bson.raw_bson.RawBSONDocument` 200 type:: 201 202 >>> from .raw_bson import RawBSONDocument 203 >>> from .codec_options import CodecOptions 204 >>> codec_options = CodecOptions(document_class=RawBSONDocument) 205 >>> coll = db.get_collection('test', codec_options=codec_options) 206 >>> doc = coll.find_one() 207 >>> doc.raw 208 '\\x16\\x00\\x00\\x00\\x07_id\\x00[0\\x165\\x91\\x10\\xea\\x14\\xe8\\xc5\\x8b\\x93\\x00' 209 210 The document class can be any type that inherits from 211 :class:`~collections.abc.MutableMapping`:: 212 213 >>> class AttributeDict(dict): 214 ... # A dict that supports attribute access. 215 ... def __getattr__(self, key): 216 ... return self[key] 217 ... def __setattr__(self, key, value): 218 ... self[key] = value 219 ... 220 >>> codec_options = CodecOptions(document_class=AttributeDict) 221 >>> coll = db.get_collection('test', codec_options=codec_options) 222 >>> doc = coll.find_one() 223 >>> doc._id 224 ObjectId('5b3016359110ea14e8c58b93') 225 226 See :doc:`/examples/datetimes` for examples using the `tz_aware` and 227 `tzinfo` options. 228 229 See :doc:`examples/uuid` for examples using the `uuid_representation` 230 option. 231 232 :Parameters: 233 - `document_class`: BSON documents returned in queries will be decoded 234 to an instance of this class. Must be a subclass of 235 :class:`~collections.abc.MutableMapping`. Defaults to :class:`dict`. 236 - `tz_aware`: If ``True``, BSON datetimes will be decoded to timezone 237 aware instances of :class:`~datetime.datetime`. Otherwise they will be 238 naive. Defaults to ``False``. 239 - `uuid_representation`: The BSON representation to use when encoding 240 and decoding instances of :class:`~uuid.UUID`. Defaults to 241 :data:`~bson.binary.UuidRepresentation.UNSPECIFIED`. New 242 applications should consider setting this to 243 :data:`~bson.binary.UuidRepresentation.STANDARD` for cross language 244 compatibility. See :ref:`handling-uuid-data-example` for details. 245 - `unicode_decode_error_handler`: The error handler to apply when 246 a Unicode-related error occurs during BSON decoding that would 247 otherwise raise :exc:`UnicodeDecodeError`. Valid options include 248 'strict', 'replace', 'backslashreplace', 'surrogateescape', and 249 'ignore'. Defaults to 'strict'. 250 - `tzinfo`: A :class:`~datetime.tzinfo` subclass that specifies the 251 timezone to/from which :class:`~datetime.datetime` objects should be 252 encoded/decoded. 253 - `type_registry`: Instance of :class:`TypeRegistry` used to customize 254 encoding and decoding behavior. 255 256 .. versionchanged:: 4.0 257 The default for `uuid_representation` was changed from 258 :const:`~bson.binary.UuidRepresentation.PYTHON_LEGACY` to 259 :const:`~bson.binary.UuidRepresentation.UNSPECIFIED`. 260 261 .. versionadded:: 3.8 262 `type_registry` attribute. 263 264 .. warning:: Care must be taken when changing 265 `unicode_decode_error_handler` from its default value ('strict'). 266 The 'replace' and 'ignore' modes should not be used when documents 267 retrieved from the server will be modified in the client application 268 and stored back to the server. 269 """ 270 271 def __new__( 272 cls, 273 document_class=dict, 274 tz_aware=False, 275 uuid_representation=UuidRepresentation.UNSPECIFIED, 276 unicode_decode_error_handler="strict", 277 tzinfo=None, 278 type_registry=None, 279 ): 280 if not (issubclass(document_class, _MutableMapping) or _raw_document_class(document_class)): 281 raise TypeError( 282 "document_class must be dict, bson.son.SON, " 283 "bson.raw_bson.RawBSONDocument, or a " 284 "sublass of collections.abc.MutableMapping" 285 ) 286 if not isinstance(tz_aware, bool): 287 raise TypeError("tz_aware must be True or False") 288 if uuid_representation not in ALL_UUID_REPRESENTATIONS: 289 raise ValueError( 290 "uuid_representation must be a value " "from .binary.UuidRepresentation" 291 ) 292 if not isinstance(unicode_decode_error_handler, (str, None)): 293 raise ValueError("unicode_decode_error_handler must be a string " "or None") 294 if tzinfo is not None: 295 if not isinstance(tzinfo, datetime.tzinfo): 296 raise TypeError("tzinfo must be an instance of datetime.tzinfo") 297 if not tz_aware: 298 raise ValueError("cannot specify tzinfo without also setting tz_aware=True") 299 300 type_registry = type_registry or TypeRegistry() 301 302 if not isinstance(type_registry, TypeRegistry): 303 raise TypeError("type_registry must be an instance of TypeRegistry") 304 305 return tuple.__new__( 306 cls, 307 ( 308 document_class, 309 tz_aware, 310 uuid_representation, 311 unicode_decode_error_handler, 312 tzinfo, 313 type_registry, 314 ), 315 ) 316 317 def _arguments_repr(self): 318 """Representation of the arguments used to create this object.""" 319 document_class_repr = "dict" if self.document_class is dict else repr(self.document_class) 320 321 uuid_rep_repr = UUID_REPRESENTATION_NAMES.get( 322 self.uuid_representation, self.uuid_representation 323 ) 324 325 return ( 326 "document_class=%s, tz_aware=%r, uuid_representation=%s, " 327 "unicode_decode_error_handler=%r, tzinfo=%r, " 328 "type_registry=%r" 329 % ( 330 document_class_repr, 331 self.tz_aware, 332 uuid_rep_repr, 333 self.unicode_decode_error_handler, 334 self.tzinfo, 335 self.type_registry, 336 ) 337 ) 338 339 def _options_dict(self): 340 """Dictionary of the arguments used to create this object.""" 341 # TODO: PYTHON-2442 use _asdict() instead 342 return { 343 "document_class": self.document_class, 344 "tz_aware": self.tz_aware, 345 "uuid_representation": self.uuid_representation, 346 "unicode_decode_error_handler": self.unicode_decode_error_handler, 347 "tzinfo": self.tzinfo, 348 "type_registry": self.type_registry, 349 } 350 351 def __repr__(self): 352 return "%s(%s)" % (self.__class__.__name__, self._arguments_repr()) 353 354 def with_options(self, **kwargs): 355 """Make a copy of this CodecOptions, overriding some options:: 356 357 >>> from .codec_options import DEFAULT_CODEC_OPTIONS 358 >>> DEFAULT_CODEC_OPTIONS.tz_aware 359 False 360 >>> options = DEFAULT_CODEC_OPTIONS.with_options(tz_aware=True) 361 >>> options.tz_aware 362 True 363 364 .. versionadded:: 3.5 365 """ 366 opts = self._options_dict() 367 opts.update(kwargs) 368 return CodecOptions(**opts) 369 370 371DEFAULT_CODEC_OPTIONS = CodecOptions() 372 373 374def _parse_codec_options(options): 375 """Parse BSON codec options.""" 376 kwargs = {} 377 for k in set(options) & { 378 "document_class", 379 "tz_aware", 380 "uuidrepresentation", 381 "unicode_decode_error_handler", 382 "tzinfo", 383 "type_registry", 384 }: 385 if k == "uuidrepresentation": 386 kwargs["uuid_representation"] = options[k] 387 else: 388 kwargs[k] = options[k] 389 return CodecOptions(**kwargs)
44class TypeEncoder(abc.ABC): 45 """Base class for defining type codec classes which describe how a 46 custom type can be transformed to one of the types BSON understands. 47 48 Codec classes must implement the ``python_type`` attribute, and the 49 ``transform_python`` method to support encoding. 50 51 See :ref:`custom-type-type-codec` documentation for an example. 52 """ 53 54 @_abstractproperty 55 def python_type(self): 56 """The Python type to be converted into something serializable.""" 57 pass 58 59 @abc.abstractmethod 60 def transform_python(self, value): 61 """Convert the given Python object into something serializable.""" 62 pass
Base class for defining type codec classes which describe how a custom type can be transformed to one of the types BSON understands.
Codec classes must implement the python_type
attribute, and the
transform_python
method to support encoding.
See :ref:custom-type-type-codec
documentation for an example.
65class TypeDecoder(abc.ABC): 66 """Base class for defining type codec classes which describe how a 67 BSON type can be transformed to a custom type. 68 69 Codec classes must implement the ``bson_type`` attribute, and the 70 ``transform_bson`` method to support decoding. 71 72 See :ref:`custom-type-type-codec` documentation for an example. 73 """ 74 75 @_abstractproperty 76 def bson_type(self): 77 """The BSON type to be converted into our own type.""" 78 pass 79 80 @abc.abstractmethod 81 def transform_bson(self, value): 82 """Convert the given BSON value into our own type.""" 83 pass
Base class for defining type codec classes which describe how a BSON type can be transformed to a custom type.
Codec classes must implement the bson_type
attribute, and the
transform_bson
method to support decoding.
See :ref:custom-type-type-codec
documentation for an example.
86class TypeCodec(TypeEncoder, TypeDecoder): 87 """Base class for defining type codec classes which describe how a 88 custom type can be transformed to/from one of the types :mod:`bson` 89 can already encode/decode. 90 91 Codec classes must implement the ``python_type`` attribute, and the 92 ``transform_python`` method to support encoding, as well as the 93 ``bson_type`` attribute, and the ``transform_bson`` method to support 94 decoding. 95 96 See :ref:`custom-type-type-codec` documentation for an example. 97 """ 98 99 pass
Base class for defining type codec classes which describe how a
custom type can be transformed to/from one of the types bson
can already encode/decode.
Codec classes must implement the python_type
attribute, and the
transform_python
method to support encoding, as well as the
bson_type
attribute, and the transform_bson
method to support
decoding.
See :ref:custom-type-type-codec
documentation for an example.
Inherited Members
102class TypeRegistry(object): 103 """Encapsulates type codecs used in encoding and / or decoding BSON, as 104 well as the fallback encoder. Type registries cannot be modified after 105 instantiation. 106 107 ``TypeRegistry`` can be initialized with an iterable of type codecs, and 108 a callable for the fallback encoder:: 109 110 >>> from .codec_options import TypeRegistry 111 >>> type_registry = TypeRegistry([Codec1, Codec2, Codec3, ...], 112 ... fallback_encoder) 113 114 See :ref:`custom-type-type-registry` documentation for an example. 115 116 :Parameters: 117 - `type_codecs` (optional): iterable of type codec instances. If 118 ``type_codecs`` contains multiple codecs that transform a single 119 python or BSON type, the transformation specified by the type codec 120 occurring last prevails. A TypeError will be raised if one or more 121 type codecs modify the encoding behavior of a built-in :mod:`bson` 122 type. 123 - `fallback_encoder` (optional): callable that accepts a single, 124 unencodable python value and transforms it into a type that 125 :mod:`bson` can encode. See :ref:`fallback-encoder-callable` 126 documentation for an example. 127 """ 128 129 def __init__(self, type_codecs=None, fallback_encoder=None): 130 self.__type_codecs = list(type_codecs or []) 131 self._fallback_encoder = fallback_encoder 132 self._encoder_map = {} 133 self._decoder_map = {} 134 135 if self._fallback_encoder is not None: 136 if not callable(fallback_encoder): 137 raise TypeError("fallback_encoder %r is not a callable" % (fallback_encoder)) 138 139 for codec in self.__type_codecs: 140 is_valid_codec = False 141 if isinstance(codec, TypeEncoder): 142 self._validate_type_encoder(codec) 143 is_valid_codec = True 144 self._encoder_map[codec.python_type] = codec.transform_python 145 if isinstance(codec, TypeDecoder): 146 is_valid_codec = True 147 self._decoder_map[codec.bson_type] = codec.transform_bson 148 if not is_valid_codec: 149 raise TypeError( 150 "Expected an instance of %s, %s, or %s, got %r instead" 151 % (TypeEncoder.__name__, TypeDecoder.__name__, TypeCodec.__name__, codec) 152 ) 153 154 def _validate_type_encoder(self, codec): 155 from . import _BUILT_IN_TYPES 156 157 for pytype in _BUILT_IN_TYPES: 158 if issubclass(codec.python_type, pytype): 159 err_msg = ( 160 "TypeEncoders cannot change how built-in types are " 161 "encoded (encoder %s transforms type %s)" % (codec, pytype) 162 ) 163 raise TypeError(err_msg) 164 165 def __repr__(self): 166 return "%s(type_codecs=%r, fallback_encoder=%r)" % ( 167 self.__class__.__name__, 168 self.__type_codecs, 169 self._fallback_encoder, 170 ) 171 172 def __eq__(self, other): 173 if not isinstance(other, type(self)): 174 return NotImplemented 175 return ( 176 (self._decoder_map == other._decoder_map) 177 and (self._encoder_map == other._encoder_map) 178 and (self._fallback_encoder == other._fallback_encoder) 179 )
Encapsulates type codecs used in encoding and / or decoding BSON, as well as the fallback encoder. Type registries cannot be modified after instantiation.
TypeRegistry
can be initialized with an iterable of type codecs, and
a callable for the fallback encoder::
>>> from .codec_options import TypeRegistry
>>> type_registry = TypeRegistry([Codec1, Codec2, Codec3, ...],
... fallback_encoder)
See :ref:custom-type-type-registry
documentation for an example.
:Parameters:
type_codecs
(optional): iterable of type codec instances. Iftype_codecs
contains multiple codecs that transform a single python or BSON type, the transformation specified by the type codec occurring last prevails. A TypeError will be raised if one or more type codecs modify the encoding behavior of a built-inbson
type.fallback_encoder
(optional): callable that accepts a single, unencodable python value and transforms it into a type thatbson
can encode. See :ref:fallback-encoder-callable
documentation for an example.
129 def __init__(self, type_codecs=None, fallback_encoder=None): 130 self.__type_codecs = list(type_codecs or []) 131 self._fallback_encoder = fallback_encoder 132 self._encoder_map = {} 133 self._decoder_map = {} 134 135 if self._fallback_encoder is not None: 136 if not callable(fallback_encoder): 137 raise TypeError("fallback_encoder %r is not a callable" % (fallback_encoder)) 138 139 for codec in self.__type_codecs: 140 is_valid_codec = False 141 if isinstance(codec, TypeEncoder): 142 self._validate_type_encoder(codec) 143 is_valid_codec = True 144 self._encoder_map[codec.python_type] = codec.transform_python 145 if isinstance(codec, TypeDecoder): 146 is_valid_codec = True 147 self._decoder_map[codec.bson_type] = codec.transform_bson 148 if not is_valid_codec: 149 raise TypeError( 150 "Expected an instance of %s, %s, or %s, got %r instead" 151 % (TypeEncoder.__name__, TypeDecoder.__name__, TypeCodec.__name__, codec) 152 )
195class CodecOptions(_options_base): 196 """Encapsulates options used encoding and / or decoding BSON. 197 198 The `document_class` option is used to define a custom type for use 199 decoding BSON documents. Access to the underlying raw BSON bytes for 200 a document is available using the :class:`~bson.raw_bson.RawBSONDocument` 201 type:: 202 203 >>> from .raw_bson import RawBSONDocument 204 >>> from .codec_options import CodecOptions 205 >>> codec_options = CodecOptions(document_class=RawBSONDocument) 206 >>> coll = db.get_collection('test', codec_options=codec_options) 207 >>> doc = coll.find_one() 208 >>> doc.raw 209 '\\x16\\x00\\x00\\x00\\x07_id\\x00[0\\x165\\x91\\x10\\xea\\x14\\xe8\\xc5\\x8b\\x93\\x00' 210 211 The document class can be any type that inherits from 212 :class:`~collections.abc.MutableMapping`:: 213 214 >>> class AttributeDict(dict): 215 ... # A dict that supports attribute access. 216 ... def __getattr__(self, key): 217 ... return self[key] 218 ... def __setattr__(self, key, value): 219 ... self[key] = value 220 ... 221 >>> codec_options = CodecOptions(document_class=AttributeDict) 222 >>> coll = db.get_collection('test', codec_options=codec_options) 223 >>> doc = coll.find_one() 224 >>> doc._id 225 ObjectId('5b3016359110ea14e8c58b93') 226 227 See :doc:`/examples/datetimes` for examples using the `tz_aware` and 228 `tzinfo` options. 229 230 See :doc:`examples/uuid` for examples using the `uuid_representation` 231 option. 232 233 :Parameters: 234 - `document_class`: BSON documents returned in queries will be decoded 235 to an instance of this class. Must be a subclass of 236 :class:`~collections.abc.MutableMapping`. Defaults to :class:`dict`. 237 - `tz_aware`: If ``True``, BSON datetimes will be decoded to timezone 238 aware instances of :class:`~datetime.datetime`. Otherwise they will be 239 naive. Defaults to ``False``. 240 - `uuid_representation`: The BSON representation to use when encoding 241 and decoding instances of :class:`~uuid.UUID`. Defaults to 242 :data:`~bson.binary.UuidRepresentation.UNSPECIFIED`. New 243 applications should consider setting this to 244 :data:`~bson.binary.UuidRepresentation.STANDARD` for cross language 245 compatibility. See :ref:`handling-uuid-data-example` for details. 246 - `unicode_decode_error_handler`: The error handler to apply when 247 a Unicode-related error occurs during BSON decoding that would 248 otherwise raise :exc:`UnicodeDecodeError`. Valid options include 249 'strict', 'replace', 'backslashreplace', 'surrogateescape', and 250 'ignore'. Defaults to 'strict'. 251 - `tzinfo`: A :class:`~datetime.tzinfo` subclass that specifies the 252 timezone to/from which :class:`~datetime.datetime` objects should be 253 encoded/decoded. 254 - `type_registry`: Instance of :class:`TypeRegistry` used to customize 255 encoding and decoding behavior. 256 257 .. versionchanged:: 4.0 258 The default for `uuid_representation` was changed from 259 :const:`~bson.binary.UuidRepresentation.PYTHON_LEGACY` to 260 :const:`~bson.binary.UuidRepresentation.UNSPECIFIED`. 261 262 .. versionadded:: 3.8 263 `type_registry` attribute. 264 265 .. warning:: Care must be taken when changing 266 `unicode_decode_error_handler` from its default value ('strict'). 267 The 'replace' and 'ignore' modes should not be used when documents 268 retrieved from the server will be modified in the client application 269 and stored back to the server. 270 """ 271 272 def __new__( 273 cls, 274 document_class=dict, 275 tz_aware=False, 276 uuid_representation=UuidRepresentation.UNSPECIFIED, 277 unicode_decode_error_handler="strict", 278 tzinfo=None, 279 type_registry=None, 280 ): 281 if not (issubclass(document_class, _MutableMapping) or _raw_document_class(document_class)): 282 raise TypeError( 283 "document_class must be dict, bson.son.SON, " 284 "bson.raw_bson.RawBSONDocument, or a " 285 "sublass of collections.abc.MutableMapping" 286 ) 287 if not isinstance(tz_aware, bool): 288 raise TypeError("tz_aware must be True or False") 289 if uuid_representation not in ALL_UUID_REPRESENTATIONS: 290 raise ValueError( 291 "uuid_representation must be a value " "from .binary.UuidRepresentation" 292 ) 293 if not isinstance(unicode_decode_error_handler, (str, None)): 294 raise ValueError("unicode_decode_error_handler must be a string " "or None") 295 if tzinfo is not None: 296 if not isinstance(tzinfo, datetime.tzinfo): 297 raise TypeError("tzinfo must be an instance of datetime.tzinfo") 298 if not tz_aware: 299 raise ValueError("cannot specify tzinfo without also setting tz_aware=True") 300 301 type_registry = type_registry or TypeRegistry() 302 303 if not isinstance(type_registry, TypeRegistry): 304 raise TypeError("type_registry must be an instance of TypeRegistry") 305 306 return tuple.__new__( 307 cls, 308 ( 309 document_class, 310 tz_aware, 311 uuid_representation, 312 unicode_decode_error_handler, 313 tzinfo, 314 type_registry, 315 ), 316 ) 317 318 def _arguments_repr(self): 319 """Representation of the arguments used to create this object.""" 320 document_class_repr = "dict" if self.document_class is dict else repr(self.document_class) 321 322 uuid_rep_repr = UUID_REPRESENTATION_NAMES.get( 323 self.uuid_representation, self.uuid_representation 324 ) 325 326 return ( 327 "document_class=%s, tz_aware=%r, uuid_representation=%s, " 328 "unicode_decode_error_handler=%r, tzinfo=%r, " 329 "type_registry=%r" 330 % ( 331 document_class_repr, 332 self.tz_aware, 333 uuid_rep_repr, 334 self.unicode_decode_error_handler, 335 self.tzinfo, 336 self.type_registry, 337 ) 338 ) 339 340 def _options_dict(self): 341 """Dictionary of the arguments used to create this object.""" 342 # TODO: PYTHON-2442 use _asdict() instead 343 return { 344 "document_class": self.document_class, 345 "tz_aware": self.tz_aware, 346 "uuid_representation": self.uuid_representation, 347 "unicode_decode_error_handler": self.unicode_decode_error_handler, 348 "tzinfo": self.tzinfo, 349 "type_registry": self.type_registry, 350 } 351 352 def __repr__(self): 353 return "%s(%s)" % (self.__class__.__name__, self._arguments_repr()) 354 355 def with_options(self, **kwargs): 356 """Make a copy of this CodecOptions, overriding some options:: 357 358 >>> from .codec_options import DEFAULT_CODEC_OPTIONS 359 >>> DEFAULT_CODEC_OPTIONS.tz_aware 360 False 361 >>> options = DEFAULT_CODEC_OPTIONS.with_options(tz_aware=True) 362 >>> options.tz_aware 363 True 364 365 .. versionadded:: 3.5 366 """ 367 opts = self._options_dict() 368 opts.update(kwargs) 369 return CodecOptions(**opts)
Encapsulates options used encoding and / or decoding BSON.
The document_class
option is used to define a custom type for use
decoding BSON documents. Access to the underlying raw BSON bytes for
a document is available using the ~bson.raw_bson.RawBSONDocument
type::
>>> from .raw_bson import RawBSONDocument
>>> from .codec_options import CodecOptions
>>> codec_options = CodecOptions(document_class=RawBSONDocument)
>>> coll = db.get_collection('test', codec_options=codec_options)
>>> doc = coll.find_one()
>>> doc.raw
'\x16\x00\x00\x00\x07_id\x00[0\x165\x91\x10\xea\x14\xe8\xc5\x8b\x93\x00'
The document class can be any type that inherits from
~collections.abc.MutableMapping
::
>>> class AttributeDict(dict):
... # A dict that supports attribute access.
... def __getattr__(self, key):
... return self[key]
... def __setattr__(self, key, value):
... self[key] = value
...
>>> codec_options = CodecOptions(document_class=AttributeDict)
>>> coll = db.get_collection('test', codec_options=codec_options)
>>> doc = coll.find_one()
>>> doc._id
ObjectId('5b3016359110ea14e8c58b93')
See :doc:/examples/datetimes
for examples using the tz_aware
and
tzinfo
options.
See :doc:examples/uuid
for examples using the uuid_representation
option.
:Parameters:
document_class
: BSON documents returned in queries will be decoded to an instance of this class. Must be a subclass of~collections.abc.MutableMapping
. Defaults todict
.tz_aware
: IfTrue
, BSON datetimes will be decoded to timezone aware instances of~datetime.datetime
. Otherwise they will be naive. Defaults toFalse
.uuid_representation
: The BSON representation to use when encoding and decoding instances of~uuid.UUID
. Defaults to~bson.binary.UuidRepresentation.UNSPECIFIED
. New applications should consider setting this to~bson.binary.UuidRepresentation.STANDARD
for cross language compatibility. See :ref:handling-uuid-data-example
for details.unicode_decode_error_handler
: The error handler to apply when a Unicode-related error occurs during BSON decoding that would otherwise raiseUnicodeDecodeError
. Valid options include 'strict', 'replace', 'backslashreplace', 'surrogateescape', and 'ignore'. Defaults to 'strict'.tzinfo
: A~datetime.tzinfo
subclass that specifies the timezone to/from which~datetime.datetime
objects should be encoded/decoded.type_registry
: Instance ofTypeRegistry
used to customize encoding and decoding behavior.
Changed in version 4.0:
The default for uuid_representation
was changed from
~bson.binary.UuidRepresentation.PYTHON_LEGACY
to
~bson.binary.UuidRepresentation.UNSPECIFIED
.
New in version 3.8:
type_registry
attribute.
Care must be taken when changing
unicode_decode_error_handler
from its default value ('strict').
The 'replace' and 'ignore' modes should not be used when documents
retrieved from the server will be modified in the client application
and stored back to the server.
355 def with_options(self, **kwargs): 356 """Make a copy of this CodecOptions, overriding some options:: 357 358 >>> from .codec_options import DEFAULT_CODEC_OPTIONS 359 >>> DEFAULT_CODEC_OPTIONS.tz_aware 360 False 361 >>> options = DEFAULT_CODEC_OPTIONS.with_options(tz_aware=True) 362 >>> options.tz_aware 363 True 364 365 .. versionadded:: 3.5 366 """ 367 opts = self._options_dict() 368 opts.update(kwargs) 369 return CodecOptions(**opts)
Make a copy of this CodecOptions, overriding some options::
>>> from .codec_options import DEFAULT_CODEC_OPTIONS
>>> DEFAULT_CODEC_OPTIONS.tz_aware
False
>>> options = DEFAULT_CODEC_OPTIONS.with_options(tz_aware=True)
>>> options.tz_aware
True
New in version 3.5.
Inherited Members
- builtins.tuple
- index
- count