diff --git a/bson/decimal128.py b/bson/decimal128.py index 92c054d878..7480f94d0a 100644 --- a/bson/decimal128.py +++ b/bson/decimal128.py @@ -20,8 +20,11 @@ import decimal import struct +from decimal import Decimal from typing import Any, Sequence, Tuple, Type, Union +from bson.codec_options import TypeDecoder, TypeEncoder + _PACK_64 = struct.Struct(" Type[Decimal]: + return Decimal + + def transform_python(self, value: Any) -> Decimal128: + return Decimal128(value) + + +class DecimalDecoder(TypeDecoder): + """Converts BSON :class:`Decimal128` to Python :class:`decimal.Decimal`. + + For example:: + opts = CodecOptions(type_registry=TypeRegistry([DecimalDecoder()])) + bson.decode(data, codec_options=opts) + + .. versionadded:: 4.15 + """ + + @property + def bson_type(self) -> Type[Decimal128]: + return Decimal128 + + def transform_bson(self, value: Any) -> decimal.Decimal: + return value.to_decimal() + + def create_decimal128_context() -> decimal.Context: """Returns an instance of :class:`decimal.Context` appropriate for working with IEEE-754 128-bit decimal floating point values. diff --git a/doc/changelog.rst b/doc/changelog.rst index e41ecc7e1b..305c989106 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -1,5 +1,12 @@ Changelog ========= +Changes in Version 4.15.0 (XXXX/XX/XX) +-------------------------------------- +PyMongo 4.15 brings a number of changes including: + +- Added :class:`bson.decimal128.DecimalEncoder` and :class:`bson.decimal128.DecimalDecoder` + to support encoding and decoding of BSON Decimal128 values to decimal.Decimal values using the TypeRegistry API. + Changes in Version 4.14.1 (2025/08/19) -------------------------------------- diff --git a/test/asynchronous/test_custom_types.py b/test/asynchronous/test_custom_types.py index 385f755a1d..82c54512cc 100644 --- a/test/asynchronous/test_custom_types.py +++ b/test/asynchronous/test_custom_types.py @@ -23,6 +23,7 @@ from random import random from typing import Any, Tuple, Type, no_type_check +from bson.decimal128 import DecimalDecoder, DecimalEncoder from gridfs.asynchronous.grid_file import AsyncGridIn, AsyncGridOut sys.path[0:0] = [""] @@ -59,29 +60,7 @@ _IS_SYNC = False -class DecimalEncoder(TypeEncoder): - @property - def python_type(self): - return Decimal - - def transform_python(self, value): - return Decimal128(value) - - -class DecimalDecoder(TypeDecoder): - @property - def bson_type(self): - return Decimal128 - - def transform_bson(self, value): - return value.to_decimal() - - -class DecimalCodec(DecimalDecoder, DecimalEncoder): - pass - - -DECIMAL_CODECOPTS = CodecOptions(type_registry=TypeRegistry([DecimalCodec()])) +DECIMAL_CODECOPTS = CodecOptions(type_registry=TypeRegistry([DecimalEncoder(), DecimalDecoder()])) class UndecipherableInt64Type: diff --git a/test/test_custom_types.py b/test/test_custom_types.py index 7360f2b18b..aba6b55119 100644 --- a/test/test_custom_types.py +++ b/test/test_custom_types.py @@ -23,6 +23,7 @@ from random import random from typing import Any, Tuple, Type, no_type_check +from bson.decimal128 import DecimalDecoder, DecimalEncoder from gridfs.synchronous.grid_file import GridIn, GridOut sys.path[0:0] = [""] @@ -59,29 +60,7 @@ _IS_SYNC = True -class DecimalEncoder(TypeEncoder): - @property - def python_type(self): - return Decimal - - def transform_python(self, value): - return Decimal128(value) - - -class DecimalDecoder(TypeDecoder): - @property - def bson_type(self): - return Decimal128 - - def transform_bson(self, value): - return value.to_decimal() - - -class DecimalCodec(DecimalDecoder, DecimalEncoder): - pass - - -DECIMAL_CODECOPTS = CodecOptions(type_registry=TypeRegistry([DecimalCodec()])) +DECIMAL_CODECOPTS = CodecOptions(type_registry=TypeRegistry([DecimalEncoder(), DecimalDecoder()])) class UndecipherableInt64Type: