-
Notifications
You must be signed in to change notification settings - Fork 421
/
Copy pathdynamodb_deserializer.py
94 lines (70 loc) · 3.29 KB
/
dynamodb_deserializer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
from decimal import Clamped, Context, Decimal, Inexact, Overflow, Rounded, Underflow
from typing import Any, Callable, Dict, Optional, Sequence, Set
# NOTE: DynamoDB supports up to 38 digits precision
# Therefore, this ensures our Decimal follows what's stored in the table
DYNAMODB_CONTEXT = Context(
Emin=-128,
Emax=126,
prec=38,
traps=[Clamped, Overflow, Inexact, Rounded, Underflow],
)
class TypeDeserializer:
"""
Deserializes DynamoDB types to Python types.
It's based on boto3's [DynamoDB TypeDeserializer](https://boto3.amazonaws.com/v1/documentation/api/latest/_modules/boto3/dynamodb/types.html).
The only notable difference is that for Binary (`B`, `BS`) values we return Python Bytes directly,
since we don't support Python 2.
"""
def deserialize(self, value: Dict) -> Any:
"""Deserialize DynamoDB data types into Python types.
Parameters
----------
value: Any
DynamoDB value to be deserialized to a python type
Here are the various conversions:
DynamoDB Python
-------- ------
{'NULL': True} None
{'BOOL': True/False} True/False
{'N': Decimal(value)} Decimal(value)
{'S': string} string
{'B': bytes} bytes
{'NS': [str(value)]} set([str(value)])
{'SS': [string]} set([string])
{'BS': [bytes]} set([bytes])
{'L': list} list
{'M': dict} dict
Parameters
----------
value: Any
DynamoDB value to be deserialized to a python type
Returns
--------
any
Python native type converted from DynamoDB type
"""
dynamodb_type = list(value.keys())[0]
deserializer: Optional[Callable] = getattr(self, f"_deserialize_{dynamodb_type}".lower(), None)
if deserializer is None:
raise TypeError(f"Dynamodb type {dynamodb_type} is not supported")
return deserializer(value[dynamodb_type])
def _deserialize_null(self, value: bool) -> None:
return None
def _deserialize_bool(self, value: bool) -> bool:
return value
def _deserialize_n(self, value: str) -> Decimal:
return DYNAMODB_CONTEXT.create_decimal(value)
def _deserialize_s(self, value: str) -> str:
return value
def _deserialize_b(self, value: bytes) -> bytes:
return value
def _deserialize_ns(self, value: Sequence[str]) -> Set[Decimal]:
return set(map(self._deserialize_n, value))
def _deserialize_ss(self, value: Sequence[str]) -> Set[str]:
return set(map(self._deserialize_s, value))
def _deserialize_bs(self, value: Sequence[bytes]) -> Set[bytes]:
return set(map(self._deserialize_b, value))
def _deserialize_l(self, value: Sequence[Dict]) -> Sequence[Any]:
return [self.deserialize(v) for v in value]
def _deserialize_m(self, value: Dict) -> Dict:
return {k: self.deserialize(v) for k, v in value.items()}