Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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


Expand Down
19 changes: 10 additions & 9 deletions src/compas/datastructures/attributes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__()
Expand All @@ -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:
Expand All @@ -48,43 +48,44 @@ 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:
Comment on lines +51 to +52
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should __len__ reflect this change?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes indeed it should

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."""

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."""

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."""

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."""

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."""

Expand Down
24 changes: 21 additions & 3 deletions tests/compas/datastructures/test_mesh.py
Original file line number Diff line number Diff line change
@@ -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

Expand All @@ -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)
Expand Down Expand Up @@ -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'