diff --git a/pynamodb/attributes.py b/pynamodb/attributes.py index e9b9a58b..a8cc25ba 100644 --- a/pynamodb/attributes.py +++ b/pynamodb/attributes.py @@ -1001,6 +1001,11 @@ def _is_attribute_container(self): # by the `_make_attribute` call during initialization of the containing class. return 'attribute_values' in self.__dict__ + def __repr__(self) -> str: + if self._is_attribute_container(): + return AttributeContainer.__repr__(self) + return Attribute.__repr__(self) + def _make_attribute(self): # WARNING! This function is only intended to be called from the __set_name__ function. if not self._is_attribute_container(): diff --git a/tests/test_attributes.py b/tests/test_attributes.py index 9f6df574..6d10cf3c 100644 --- a/tests/test_attributes.py +++ b/tests/test_attributes.py @@ -606,6 +606,21 @@ class TestMapAttribute: """ Tests map with str, int, float """ + @pytest.mark.parametrize('name', ['map_attr', 'raw_map_attr']) + def test_descriptor_repr(self, name: str) -> None: + attributes = AttributeTestModel.get_attributes() + attr = attributes[name] + assert repr(attr) == object.__repr__(attr) + assert object.__repr__(attr) in repr(attributes) + + @pytest.mark.parametrize('attr, expected', [ + (MapAttribute(), 'MapAttribute()'), + (MapAttribute(value='test'), "MapAttribute(value='test')"), + (AttributeTestMapAttribute(string='test'), "AttributeTestMapAttribute(string='test')"), + ]) + def test_container_repr(self, attr: MapAttribute, expected: str) -> None: + assert repr(attr) == expected + def test_attribute_children(self): person_attribute = { 'name': 'Justin',