Skip to content

Commit b6b9d24

Browse files
committed
PYTHON-5508 - Add built-in DecimalEncoder and DecimalDecoder
1 parent f7b94be commit b6b9d24

File tree

4 files changed

+49
-46
lines changed

4 files changed

+49
-46
lines changed

bson/decimal128.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,11 @@
2020

2121
import decimal
2222
import struct
23+
from decimal import Decimal
2324
from typing import Any, Sequence, Tuple, Type, Union
2425

26+
from bson.codec_options import TypeDecoder, TypeEncoder
27+
2528
_PACK_64 = struct.Struct("<Q").pack
2629
_UNPACK_64 = struct.Struct("<Q").unpack
2730

@@ -58,6 +61,38 @@
5861
_VALUE_OPTIONS = Union[decimal.Decimal, float, str, Tuple[int, Sequence[int], int]]
5962

6063

64+
class DecimalEncoder(TypeEncoder):
65+
"""Converts Python :class:`decimal.Decimal` to BSON :class:`Decimal128`.
66+
67+
.. warning:: When converting BSON data types to and from built-in data types,
68+
the possibility of data loss is always present due to mismatches in underlying implementations.
69+
70+
.. versionadded:: 4.15"""
71+
72+
@property
73+
def python_type(self):
74+
return Decimal
75+
76+
def transform_python(self, value):
77+
return Decimal128(value)
78+
79+
80+
class DecimalDecoder(TypeDecoder):
81+
"""Converts BSON :class:`Decimal128` to Python :class:`decimal.Decimal`.
82+
83+
.. warning:: When converting BSON data types to and from built-in data types,
84+
the possibility of data loss is always present due to mismatches in underlying implementations.
85+
86+
.. versionadded:: 4.15"""
87+
88+
@property
89+
def bson_type(self):
90+
return Decimal128
91+
92+
def transform_bson(self, value):
93+
return value.to_decimal()
94+
95+
6196
def create_decimal128_context() -> decimal.Context:
6297
"""Returns an instance of :class:`decimal.Context` appropriate
6398
for working with IEEE-754 128-bit decimal floating point values.

doc/changelog.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,15 @@
11
Changelog
22
=========
3+
Changes in Version 4.15.0 (XXXX/XX/XX)
4+
--------------------------------------
5+
.. warning:: When converting BSON data types to and from built-in data types, the possibility of data loss is always present
6+
due to mismatches in underlying implementations.
7+
8+
PyMongo 4.15 brings a number of changes including:
9+
10+
- Added :class:`bson.decimal128.DecimalEncoder` and :class:`bson.decimal128.DecimalDecoder`
11+
to support encoding and decoding of BSON Decimal128 values to decimal.Decimal values using the TypeRegistry API.
12+
313
Changes in Version 4.14.1 (2025/08/19)
414
--------------------------------------
515

test/asynchronous/test_custom_types.py

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from random import random
2424
from typing import Any, Tuple, Type, no_type_check
2525

26+
from bson.decimal128 import DecimalDecoder, DecimalEncoder
2627
from gridfs.asynchronous.grid_file import AsyncGridIn, AsyncGridOut
2728

2829
sys.path[0:0] = [""]
@@ -59,29 +60,7 @@
5960
_IS_SYNC = False
6061

6162

62-
class DecimalEncoder(TypeEncoder):
63-
@property
64-
def python_type(self):
65-
return Decimal
66-
67-
def transform_python(self, value):
68-
return Decimal128(value)
69-
70-
71-
class DecimalDecoder(TypeDecoder):
72-
@property
73-
def bson_type(self):
74-
return Decimal128
75-
76-
def transform_bson(self, value):
77-
return value.to_decimal()
78-
79-
80-
class DecimalCodec(DecimalDecoder, DecimalEncoder):
81-
pass
82-
83-
84-
DECIMAL_CODECOPTS = CodecOptions(type_registry=TypeRegistry([DecimalCodec()]))
63+
DECIMAL_CODECOPTS = CodecOptions(type_registry=TypeRegistry([DecimalEncoder(), DecimalDecoder()]))
8564

8665

8766
class UndecipherableInt64Type:

test/test_custom_types.py

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
from random import random
2424
from typing import Any, Tuple, Type, no_type_check
2525

26+
from bson.decimal128 import DecimalDecoder, DecimalEncoder
2627
from gridfs.synchronous.grid_file import GridIn, GridOut
2728

2829
sys.path[0:0] = [""]
@@ -59,29 +60,7 @@
5960
_IS_SYNC = True
6061

6162

62-
class DecimalEncoder(TypeEncoder):
63-
@property
64-
def python_type(self):
65-
return Decimal
66-
67-
def transform_python(self, value):
68-
return Decimal128(value)
69-
70-
71-
class DecimalDecoder(TypeDecoder):
72-
@property
73-
def bson_type(self):
74-
return Decimal128
75-
76-
def transform_bson(self, value):
77-
return value.to_decimal()
78-
79-
80-
class DecimalCodec(DecimalDecoder, DecimalEncoder):
81-
pass
82-
83-
84-
DECIMAL_CODECOPTS = CodecOptions(type_registry=TypeRegistry([DecimalCodec()]))
63+
DECIMAL_CODECOPTS = CodecOptions(type_registry=TypeRegistry([DecimalEncoder(), DecimalDecoder()]))
8564

8665

8766
class UndecipherableInt64Type:

0 commit comments

Comments
 (0)