diff --git a/CHANGELOG.md b/CHANGELOG.md index c10900a99cf0..96464b7e5290 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +* Fix bug in `compas.datastructures.AttributesView`. + ### Removed diff --git a/src/compas/datastructures/attributes.py b/src/compas/datastructures/attributes.py index 00c4f3abf1b0..3426419b41ed 100644 --- a/src/compas/datastructures/attributes.py +++ b/src/compas/datastructures/attributes.py @@ -13,8 +13,8 @@ ] -class AttributeView(object): - """Mixin for attribute dict views.""" +class AttributeView(MutableMapping): + """Base class for attribute dict views.""" def __init__(self, defaults, attr, custom_only=False): super(AttributeView, self).__init__() @@ -29,7 +29,7 @@ def __str__(self): return "{" + ", ".join(s) + "}" def __len__(self): - return len(self.defaults) + return len(set(self.defaults).union(self.attr)) def __getitem__(self, name): if name not in self.attr: @@ -48,11 +48,12 @@ def __iter__(self): for name in self.attr: yield name else: - for name in self.defaults: + names = set(self.defaults).union(self.attr) + for name in names: yield name -class NodeAttributeView(AttributeView, MutableMapping): +class NodeAttributeView(AttributeView): """Mutable Mapping that provides a read/write view of the custom attributes of a node combined with the default attributes of all nodes.""" @@ -60,7 +61,7 @@ def __init__(self, defaults, attr, custom_only=False): super(NodeAttributeView, self).__init__(defaults, attr, custom_only) -class VertexAttributeView(AttributeView, MutableMapping): +class VertexAttributeView(AttributeView): """Mutable Mapping that provides a read/write view of the custom attributes of a vertex combined with the default attributes of all vertices.""" @@ -68,7 +69,7 @@ def __init__(self, defaults, attr, custom_only=False): super(VertexAttributeView, self).__init__(defaults, attr, custom_only) -class EdgeAttributeView(AttributeView, MutableMapping): +class EdgeAttributeView(AttributeView): """Mutable Mapping that provides a read/write view of the custom attributes of an edge combined with the default attributes of all edges.""" @@ -76,7 +77,7 @@ def __init__(self, defaults, attr, custom_only=False): super(EdgeAttributeView, self).__init__(defaults, attr, custom_only) -class FaceAttributeView(AttributeView, MutableMapping): +class FaceAttributeView(AttributeView): """Mutable Mapping that provides a read/write view of the custom attributes of a face combined with the default attributes of all faces.""" @@ -84,7 +85,7 @@ def __init__(self, defaults, attr, custom_only=False): super(FaceAttributeView, self).__init__(defaults, attr, custom_only) -class CellAttributeView(AttributeView, MutableMapping): +class CellAttributeView(AttributeView): """Mutable Mapping that provides a read/write view of the custom attributes of a cell combined with the default attributes of all faces.""" diff --git a/tests/compas/datastructures/test_mesh.py b/tests/compas/datastructures/test_mesh.py index 9483a7c2bc50..2f9309e69f41 100644 --- a/tests/compas/datastructures/test_mesh.py +++ b/tests/compas/datastructures/test_mesh.py @@ -1,11 +1,12 @@ -# import pytest -import os -import compas import json +import os + import pytest +import compas from compas.datastructures import Mesh from compas.datastructures import meshes_join_and_weld +from compas.geometry import Box from compas.geometry import Polygon from compas.geometry import Translation @@ -20,6 +21,12 @@ def cube(): return Mesh.from_polyhedron(6) +@pytest.fixture +def box(): + box = Box.from_width_height_depth(2, 2, 2) + return Mesh.from_shape(box) + + @pytest.fixture def hexagon(): polygon = Polygon.from_sides_and_radius_xy(6, 1) @@ -666,3 +673,14 @@ def test_faces_on_boundaries_triangleboundarychain(triangleboundarychain): # -------------------------------------------------------------------------- # attributes # -------------------------------------------------------------------------- + +def test_face_attributes_includes_all_defaults(box): + box.update_default_face_attributes({"attr1": "value1", "attr2": "value2"}) + + random_fkey = box.get_any_face() + assert sorted(box.face_attributes(random_fkey).keys()) == ['attr1', 'attr2'] + + box.face_attribute(random_fkey, "attr3", "value3") + assert sorted(box.face_attributes(random_fkey).keys()) == ['attr1', 'attr2', 'attr3'] + + assert box.face_attribute(random_fkey, "attr3") == 'value3'