PYTHON-5508 - Add built-in DecimalEncoder and DecimalDecoder (#2499)

This commit is contained in:
Noah Stapp 2025-08-21 06:51:00 -07:00 committed by GitHub
parent 9a9a65c617
commit 5e96353797
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 50 additions and 46 deletions

View File

@ -20,8 +20,11 @@ from __future__ import annotations
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("<Q").pack
_UNPACK_64 = struct.Struct("<Q").unpack
@ -58,6 +61,42 @@ _DEC128_CTX = decimal.Context(**_CTX_OPTIONS.copy()) # type: ignore
_VALUE_OPTIONS = Union[decimal.Decimal, float, str, Tuple[int, Sequence[int], int]]
class DecimalEncoder(TypeEncoder):
"""Converts Python :class:`decimal.Decimal` to BSON :class:`Decimal128`.
For example::
opts = CodecOptions(type_registry=TypeRegistry([DecimalEncoder()]))
bson.encode({"d": decimal.Decimal('1.0')}, codec_options=opts)
.. versionadded:: 4.15
"""
@property
def python_type(self) -> 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.

View File

@ -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)
--------------------------------------

View File

@ -23,6 +23,7 @@ from decimal import Decimal
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 @@ from pymongo.message import _CursorAddress
_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:

View File

@ -23,6 +23,7 @@ from decimal import Decimal
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 @@ from pymongo.synchronous.helpers import next
_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: