Coverage for pyodmongo/models/db_decimal.py: 100%
28 statements
« prev ^ index » next coverage.py v7.7.1, created at 2025-03-27 14:31 +0000
« prev ^ index » next coverage.py v7.7.1, created at 2025-03-27 14:31 +0000
1from typing import Any
2from bson import Decimal128
3from decimal import Decimal, Context, localcontext
4from pydantic import GetCoreSchemaHandler
5from pydantic_core import core_schema, CoreSchema
6from pydantic_core.core_schema import ValidationInfo, str_schema, float_schema
9class DbDecimal(Decimal):
10 def __new__(cls, value: Any, scale: None | int = None):
11 if isinstance(value, Decimal128):
12 value = value.to_decimal()
13 elif isinstance(value, (int, float, str, Decimal)):
14 _DEC128_CTX = Context(prec=34)
15 with localcontext(_DEC128_CTX) as ctx:
16 value = ctx.create_decimal(value)
17 if scale:
18 quantizer = Decimal("0." + ("0" * scale))
19 value = value.quantize(quantizer)
20 else:
21 raise ValueError("Invalid decimal type")
22 return super().__new__(cls, value)
24 def to_scale(self, scale: int):
25 quantizer = Decimal("0." + ("0" * scale))
26 return self.quantize(quantizer)
28 @classmethod
29 def validate(cls, v, _: ValidationInfo):
30 return cls(v)
32 @classmethod
33 def __get_pydantic_core_schema__(
34 cls, source_type: Any, handler: GetCoreSchemaHandler
35 ) -> CoreSchema: # type: ignore
36 return core_schema.json_or_python_schema(
37 python_schema=core_schema.with_info_plain_validator_function(cls.validate),
38 json_schema=float_schema(),
39 serialization=core_schema.plain_serializer_function_ser_schema(
40 lambda v: float(v) if isinstance(v, Decimal) else v, when_used="json"
41 ),
42 )