3838
3939_logger = logging .getLogger (__name__ )
4040
41-
42- def _clean_attribute (
43- key : str , value : types .AttributeValue , max_len : Optional [int ]
44- ) -> Optional [Union [types .AttributeValue , Tuple [Union [str , int , float ], ...]]]:
45- """Checks if attribute value is valid and cleans it if required.
46-
47- The function returns the cleaned value or None if the value is not valid.
48-
49- An attribute value is valid if it is either:
50- - A primitive type: string, boolean, double precision floating
51- point (IEEE 754-1985) or integer.
52- - An array of primitive type values. The array MUST be homogeneous,
53- i.e. it MUST NOT contain values of different types.
54-
55- An attribute needs cleansing if:
56- - Its length is greater than the maximum allowed length.
57- - It needs to be encoded/decoded e.g, bytes to strings.
58- """
59-
60- if not (key and isinstance (key , str )):
61- _logger .warning ("invalid key `%s`. must be non-empty string." , key )
62- return None
63-
64- if isinstance (value , _VALID_ATTR_VALUE_TYPES ):
65- return _clean_attribute_value (value , max_len )
66-
67- if isinstance (value , Sequence ):
68- sequence_first_valid_type = None
69- cleaned_seq = []
70-
71- for element in value :
72- element = _clean_attribute_value (element , max_len ) # type: ignore
73- if element is None :
74- cleaned_seq .append (element )
75- continue
76-
77- element_type = type (element )
78- # Reject attribute value if sequence contains a value with an incompatible type.
79- if element_type not in _VALID_ATTR_VALUE_TYPES :
80- _logger .warning (
81- "Invalid type %s in attribute '%s' value sequence. Expected one of "
82- "%s or None" ,
83- element_type .__name__ ,
84- key ,
85- [
86- valid_type .__name__
87- for valid_type in _VALID_ATTR_VALUE_TYPES
88- ],
89- )
90- return None
91-
92- # The type of the sequence must be homogeneous. The first non-None
93- # element determines the type of the sequence
94- if sequence_first_valid_type is None :
95- sequence_first_valid_type = element_type
96- # use equality instead of isinstance as isinstance(True, int) evaluates to True
97- elif element_type != sequence_first_valid_type :
98- _logger .warning (
99- "Attribute %r mixes types %s and %s in attribute value sequence" ,
100- key ,
101- sequence_first_valid_type .__name__ ,
102- type (element ).__name__ ,
103- )
104- return None
105-
106- cleaned_seq .append (element )
107-
108- # Freeze mutable sequences defensively
109- return tuple (cleaned_seq )
110-
111- _logger .warning (
112- "Invalid type %s for attribute '%s' value. Expected one of %s or a "
113- "sequence of those types" ,
114- type (value ).__name__ ,
115- key ,
116- [valid_type .__name__ for valid_type in _VALID_ATTR_VALUE_TYPES ],
117- )
118- return None
119-
120-
12141def _clean_extended_attribute_value (
12242 value : types .AnyValue , max_len : Optional [int ]
12343) -> types .AnyValue :
@@ -209,25 +129,6 @@ def _clean_extended_attribute(
209129 _logger .warning ("Attribute %s: %s" , key , exception )
210130 return None
211131
212-
213- def _clean_attribute_value (
214- value : types .AttributeValue , limit : Optional [int ]
215- ) -> Optional [types .AttributeValue ]:
216- if value is None :
217- return None
218-
219- if isinstance (value , bytes ):
220- try :
221- value = value .decode ()
222- except UnicodeDecodeError :
223- _logger .warning ("Byte attribute could not be decoded." )
224- return None
225-
226- if limit is not None and isinstance (value , str ):
227- value = value [:limit ]
228- return value
229-
230-
231132class BoundedAttributes (MutableMapping ): # type: ignore
232133 """An ordered dict with a fixed max capacity.
233134
@@ -251,7 +152,7 @@ def __init__(
251152 self .maxlen = maxlen
252153 self .dropped = 0
253154 self .max_value_len = max_value_len
254- self ._extended_attributes = extended_attributes
155+ self ._extended_attributes = True
255156 # OrderedDict is not used until the maxlen is reached for efficiency.
256157
257158 self ._dict : Union [
@@ -278,14 +179,9 @@ def __setitem__(self, key: str, value: types.AnyValue) -> None:
278179 self .dropped += 1
279180 return
280181
281- if self ._extended_attributes :
282- value = _clean_extended_attribute (
283- key , value , self .max_value_len
284- )
285- else :
286- value = _clean_attribute (key , value , self .max_value_len ) # type: ignore
287- if value is None :
288- return
182+ value = _clean_extended_attribute (
183+ key , value , self .max_value_len
184+ )
289185
290186 if key in self ._dict :
291187 del self ._dict [key ]
0 commit comments