Skip to content

Commit 0557f7b

Browse files
committed
feat: Add __str__ to Data Classes base DictWrapper
Add in a __str__ method to the base class used by all Data Classes. This provides a dictionary string primarily for debugging purposes. To construct the dictionary a helper method _str_helper recursively works through `properties` in each instance of a Data Class. Some Data Classes have sensitive properties, such as credentials, which can be excluded by setting the `_str_blacklist` attribute (list of strings). These properties will have their value replaced with "[SENSITIVE]", which allows a developer to see a value arrived, but was hidden as it is sensitive.
1 parent 3e313bb commit 0557f7b

File tree

1 file changed

+44
-1
lines changed
  • aws_lambda_powertools/utilities/data_classes

1 file changed

+44
-1
lines changed

aws_lambda_powertools/utilities/data_classes/common.py

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import base64
22
import json
33
from collections.abc import Mapping
4-
from typing import Any, Dict, Iterator, Optional
4+
from typing import Any, Dict, Iterator, List, Optional
55

66
from aws_lambda_powertools.shared.headers_serializer import BaseHeadersSerializer
77

@@ -28,6 +28,49 @@ def __iter__(self) -> Iterator:
2828
def __len__(self) -> int:
2929
return len(self._data)
3030

31+
def __str__(self) -> str:
32+
return str(self._str_helper())
33+
34+
def _str_helper(self) -> Dict[str, Any]:
35+
"""
36+
Recursively get a Dictionary of DictWrapper properties primarily
37+
for use by __str__ for debugging purposes.
38+
39+
Will remove "raw_event" properties, and any defined by the Data Class
40+
`_str_sensitive_data` list field.
41+
This should be used in case where secrets, such as access keys, are
42+
stored in the Data Class but should not be logged out.
43+
"""
44+
properties = self._properties()
45+
sensitive_properties = ["raw_event"]
46+
try:
47+
sensitive_properties.extend(self.__getattribute__("_str_sensitive_data"))
48+
except AttributeError:
49+
pass
50+
51+
result: Dict[str, Any] = {}
52+
for property_key in properties:
53+
if property_key in sensitive_properties:
54+
result[property_key] = "[SENSITIVE]"
55+
else:
56+
try:
57+
property_value = getattr(self, property_key)
58+
result[property_key] = property_value
59+
60+
if issubclass(property_value.__class__, DictWrapper):
61+
result[property_key] = property_value._str_helper()
62+
elif isinstance(property_value, list):
63+
for seq, item in enumerate(property_value):
64+
if issubclass(item.__class__, DictWrapper):
65+
result[property_key][seq] = item._str_helper()
66+
except Exception as e:
67+
result[property_key] = f"[EXCEPTION {type(e)}]"
68+
69+
return result
70+
71+
def _properties(self) -> List[str]:
72+
return [p for p in dir(self.__class__) if isinstance(getattr(self.__class__, p), property)]
73+
3174
def get(self, key: str, default: Optional[Any] = None) -> Optional[Any]:
3275
return self._data.get(key, default)
3376

0 commit comments

Comments
 (0)