Skip to content

Commit

Permalink
Refine tree type hierarchy, fix some docstrings (#353)
Browse files Browse the repository at this point in the history
Removes the `NamedTreeObject` class and implements the `name` attribute
in `TreeObjectBase` instead, since `TreeObjectBase` was already relying on
the existence of the name.

Adds a `doc` parameter to all gRPC property helpers, which is then set
as `__doc__` attribute on the created property.
This was previously defined only for `grpc_data_property_read_only`.

Improve some docstrings.
  • Loading branch information
greschd authored Jan 26, 2024
1 parent ba544a2 commit 62ec7ae
Show file tree
Hide file tree
Showing 9 changed files with 105 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from typing_extensions import Self

from ..base import CreatableTreeObject
from .property_helper import _exposed_grpc_property, grpc_data_getter, grpc_data_setter
from .property_helper import _exposed_grpc_property, _wrap_doc, grpc_data_getter, grpc_data_setter

__all__ = ["EdgePropertyList", "define_edge_property_list", "GenericEdgePropertyType"]

Expand Down Expand Up @@ -228,7 +228,7 @@ def __repr__(self) -> str:


def define_edge_property_list(
attribute_name: str, value_type: type[GenericEdgePropertyType]
attribute_name: str, value_type: type[GenericEdgePropertyType], doc: str | None = None
) -> Any:
def getter(self: CreatableTreeObject) -> EdgePropertyList[GenericEdgePropertyType]:
return EdgePropertyList(
Expand All @@ -241,4 +241,4 @@ def getter(self: CreatableTreeObject) -> EdgePropertyList[GenericEdgePropertyTyp
def setter(self: CreatableTreeObject, value: list[GenericEdgePropertyType]) -> None:
getter(self)[:] = value

return _exposed_grpc_property(getter).setter(setter)
return _wrap_doc(_exposed_grpc_property(getter).setter(setter), doc=doc)
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

from ..base import CreatableTreeObject, TreeObject
from .polymorphic_from_pb import tree_object_from_resource_path
from .property_helper import _exposed_grpc_property, grpc_data_getter, grpc_data_setter
from .property_helper import _exposed_grpc_property, _wrap_doc, grpc_data_getter, grpc_data_setter

ValueT = TypeVar("ValueT", bound=CreatableTreeObject)

Expand Down Expand Up @@ -155,7 +155,9 @@ def __eq__(self, other: Any) -> Any:
ChildT = TypeVar("ChildT", bound=CreatableTreeObject)


def define_linked_object_list(attribute_name: str, object_class: type[ChildT]) -> Any:
def define_linked_object_list(
attribute_name: str, object_class: type[ChildT], doc: str | None = None
) -> Any:
def getter(self: ValueT) -> LinkedObjectList[ChildT]:
return LinkedObjectList(
parent_object=self,
Expand All @@ -166,7 +168,7 @@ def getter(self: ValueT) -> LinkedObjectList[ChildT]:
def setter(self: ValueT, value: list[ChildT]) -> None:
getter(self)[:] = value

return _exposed_grpc_property(getter).setter(setter)
return _wrap_doc(_exposed_grpc_property(getter).setter(setter), doc=doc)


def define_polymorphic_linked_object_list(
Expand Down
41 changes: 24 additions & 17 deletions src/ansys/acp/core/_tree_objects/_grpc_helpers/mapping.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@

from ..._utils.property_protocols import ReadOnlyProperty
from ..._utils.resource_paths import join as _rp_join
from ..base import CreatableTreeObject, TreeObject
from ..base import CreatableTreeObject, TreeObject, TreeObjectBase
from .exceptions import wrap_grpc_errors
from .property_helper import _exposed_grpc_property, _wrap_doc
from .protocols import EditableAndReadableResourceStub, ObjectInfo, ReadableResourceStub

ValueT = TypeVar("ValueT", bound=CreatableTreeObject)
ValueT = TypeVar("ValueT", bound=TreeObjectBase)
CreatableValueT = TypeVar("CreatableValueT", bound=CreatableTreeObject)

__all__ = ["Mapping", "MutableMapping", "define_mutable_mapping", "define_create_method"]

Expand Down Expand Up @@ -99,14 +101,14 @@ def get(self, key: str, default: ValueT | None = None) -> ValueT | None:
return default


class MutableMapping(Mapping[ValueT]):
class MutableMapping(Mapping[CreatableValueT]):
def __init__(
self,
*,
channel: Channel,
collection_path: CollectionPath,
stub: EditableAndReadableResourceStub,
object_constructor: Callable[[ObjectInfo, Channel | None], ValueT],
object_constructor: Callable[[ObjectInfo, Channel | None], CreatableValueT],
) -> None:
self._collection_path = collection_path
self._stub: EditableAndReadableResourceStub = stub
Expand All @@ -132,15 +134,15 @@ def clear(self) -> None:
)
)

def pop(self, key: str) -> ValueT:
def pop(self, key: str) -> CreatableValueT:
obj_info = self._get_objectinfo_by_id(key)
return self._pop_from_info(obj_info)

def popitem(self) -> ValueT:
def popitem(self) -> CreatableValueT:
obj_info = self._get_objectinfo_list()[0]
return self._pop_from_info(obj_info)

def _pop_from_info(self, object_info: ObjectInfo) -> ValueT:
def _pop_from_info(self, object_info: ObjectInfo) -> CreatableValueT:
obj = self._object_constructor(object_info, self._channel)
new_obj = obj.clone()
obj.delete()
Expand All @@ -151,8 +153,8 @@ def _pop_from_info(self, object_info: ObjectInfo) -> ValueT:


def get_read_only_collection_property(
object_class: type[ValueT], stub_class: type[ReadableResourceStub]
) -> Callable[[ParentT], Mapping[ValueT]]:
object_class: type[ValueT], stub_class: type[ReadableResourceStub], doc: str | None = None
) -> ReadOnlyProperty[Mapping[ValueT]]:
def collection_property(self: ParentT) -> Mapping[ValueT]:
return Mapping(
channel=self._channel,
Expand All @@ -163,16 +165,19 @@ def collection_property(self: ParentT) -> Mapping[ValueT]:
stub=stub_class(channel=self._channel),
)

return collection_property
return _wrap_doc(_exposed_grpc_property(collection_property), doc=doc)


P = ParamSpec("P")


def define_create_method(
object_class: Callable[P, ValueT], func_name: str, parent_class_name: str, module_name: str
) -> Callable[Concatenate[ParentT, P], ValueT]:
def inner(self: ParentT, /, *args: P.args, **kwargs: P.kwargs) -> ValueT:
object_class: Callable[P, CreatableValueT],
func_name: str,
parent_class_name: str,
module_name: str,
) -> Callable[Concatenate[ParentT, P], CreatableValueT]:
def inner(self: ParentT, /, *args: P.args, **kwargs: P.kwargs) -> CreatableValueT:
obj = object_class(*args, **kwargs)
obj.store(parent=self)
return obj
Expand All @@ -188,9 +193,11 @@ def inner(self: ParentT, /, *args: P.args, **kwargs: P.kwargs) -> ValueT:


def define_mutable_mapping(
object_class: type[ValueT], stub_class: type[EditableAndReadableResourceStub]
) -> ReadOnlyProperty[MutableMapping[ValueT]]:
def collection_property(self: ParentT) -> MutableMapping[ValueT]:
object_class: type[CreatableValueT],
stub_class: type[EditableAndReadableResourceStub],
doc: str | None = None,
) -> ReadOnlyProperty[MutableMapping[CreatableValueT]]:
def collection_property(self: ParentT) -> MutableMapping[CreatableValueT]:
return MutableMapping(
channel=self._channel,
collection_path=CollectionPath(
Expand All @@ -200,4 +207,4 @@ def collection_property(self: ParentT) -> MutableMapping[ValueT]:
stub=stub_class(channel=self._channel),
)

return property(collection_property)
return _wrap_doc(_exposed_grpc_property(collection_property), doc=doc)
40 changes: 31 additions & 9 deletions src/ansys/acp/core/_tree_objects/_grpc_helpers/property_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,23 +238,45 @@ def grpc_data_property_read_only(
)


def grpc_link_property(name: str) -> Any:
def grpc_link_property(
name: str,
doc: str | None = None,
) -> Any:
"""
Helper for defining linked properties accessed via gRPC. The property getter
makes call to the gRPC Get endpoints to get the linked object
Parameters
----------
name :
Name of the property.
doc :
Docstring for the property.
"""
return _exposed_grpc_property(grpc_linked_object_getter(name)).setter(
# Resource path represents an object that is not set as an empty string
grpc_data_setter(
name=name,
to_protobuf=lambda obj: ResourcePath(value="") if obj is None else obj._resource_path,
)
return _wrap_doc(
_exposed_grpc_property(grpc_linked_object_getter(name)).setter(
# Resource path represents an object that is not set as an empty string
grpc_data_setter(
name=name,
to_protobuf=lambda obj: ResourcePath(value="")
if obj is None
else obj._resource_path,
)
),
doc=doc,
)


def grpc_link_property_read_only(name: str) -> Any:
def grpc_link_property_read_only(name: str, doc: str | None = None) -> Any:
"""
Helper for defining linked properties accessed via gRPC. The property getter
makes call to the gRPC Get endpoints to get the linked object
Parameters
----------
name :
Name of the property.
doc :
Docstring for the property.
"""
return _exposed_grpc_property(grpc_linked_object_getter(name))
return _wrap_doc(_exposed_grpc_property(grpc_linked_object_getter(name)), doc=doc)
38 changes: 20 additions & 18 deletions src/ansys/acp/core/_tree_objects/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
_T = TypeVar("_T", bound="TreeObjectBase")


@mark_grpc_properties
class TreeObjectBase(GrpcObjectBase):
"""
Base class for ACP tree objects.
Expand All @@ -51,12 +52,15 @@ class TreeObjectBase(GrpcObjectBase):
OBJECT_INFO_TYPE: type[ObjectInfo]

_pb_object: ObjectInfo
name: ReadWriteProperty[str, str]
name: ReadOnlyProperty[str]

def __init__(self: TreeObjectBase, name: str = "") -> None:
self._channel_store: Channel | None = None
self._pb_object: ObjectInfo = self.OBJECT_INFO_TYPE()
self.name = name
# We don't want to invoke gRPC requests for setting the name
# during object construction, so we set the name directly on
# the protobuf object.
self._pb_object.info.name = name

def clone(self: _T, *, unlink: bool = False) -> _T:
"""Create a new unstored object with the same properties.
Expand Down Expand Up @@ -113,6 +117,11 @@ def _channel(self) -> Channel:
def _is_stored(self) -> bool:
return self._channel_store is not None

def __repr__(self) -> str:
return f"<{type(self).__name__} with name '{self.name}'>"

name = grpc_data_property_read_only("info.name", doc="The name of the object.")


StubT = TypeVar("StubT")

Expand All @@ -130,21 +139,11 @@ def get(self, is_stored: bool) -> StubT:
return self._stub_store


@mark_grpc_properties
class NamedTreeObject(GrpcObjectBase):
__slots__: Iterable[str] = tuple()

"""Implements the 'name' attribute for tree objects."""

name: ReadWriteProperty[str, str] = grpc_data_property("info.name")
"""The name of the object."""

def __repr__(self) -> str:
return f"<{type(self).__name__} with name '{self.name}'>"


class TreeObject(TreeObjectBase, NamedTreeObject):
class TreeObject(TreeObjectBase):
__slots__: Iterable[str] = ("_stub_store",)
name: ReadWriteProperty[str, str] = grpc_data_property(
"info.name", doc="The name of the object."
)

@abstractmethod
def _create_stub(self) -> EditableAndReadableResourceStub:
Expand Down Expand Up @@ -185,7 +184,8 @@ def _get_stub(self) -> EditableAndReadableResourceStub:
return self._stub_store.get(self._is_stored)


class ReadOnlyTreeObject(TreeObjectBase, NamedTreeObject):
@mark_grpc_properties
class ReadOnlyTreeObject(TreeObjectBase):
def __init__(self: ReadOnlyTreeObject) -> None:
super().__init__()
self._stub_store = StubStore(self._create_stub)
Expand Down Expand Up @@ -257,7 +257,9 @@ class IdTreeObject(TreeObjectBase):

__slots__: Iterable[str] = tuple()

id: ReadOnlyProperty[str] = grpc_data_property_read_only("info.id")
id: ReadOnlyProperty[str] = grpc_data_property_read_only(
"info.id", doc="Identifier of the object, used for example as key in maps."
)

def __repr__(self) -> str:
return f"<{type(self).__name__} with id '{self.id}'>"
Expand Down
4 changes: 2 additions & 2 deletions src/ansys/acp/core/_tree_objects/cad_geometry.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,8 +141,8 @@ def visualization_mesh(self) -> TriangleMesh:
)
return TriangleMesh._from_pb(response)

root_shapes = property(
get_read_only_collection_property(CADComponent, cad_component_pb2_grpc.ObjectServiceStub)
root_shapes = get_read_only_collection_property(
CADComponent, cad_component_pb2_grpc.ObjectServiceStub
)

def refresh(self) -> None:
Expand Down
23 changes: 12 additions & 11 deletions src/ansys/acp/core/_tree_objects/element_set.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ class ElementSetNodalData(NodalData):
@mark_grpc_properties
@register
class ElementSet(CreatableTreeObject, IdTreeObject):
"""Instantiate an Element Set.
Parameters
----------
name :
The name of the Element Set.
middle_offset :
TODO
element_labels :
TODO
"""

__slots__: Iterable[str] = tuple()
_COLLECTION_LABEL = "element_sets"
OBJECT_INFO_TYPE = element_set_pb2.ObjectInfo
Expand All @@ -54,17 +66,6 @@ def __init__(
middle_offset: bool = False,
element_labels: Collection[int] = tuple(),
):
"""Instantiate an Element Set.
Parameters
----------
name :
The name of the Element Set.
middle_offset :
TODO
element_labels :
TODO
"""
super().__init__(name=name)
self.middle_offset = middle_offset
self.element_labels = element_labels
Expand Down
10 changes: 6 additions & 4 deletions src/ansys/acp/core/_tree_objects/modeling_ply.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,12 @@ def __repr__(self) -> str:
@mark_grpc_properties
@register
class ModelingPly(CreatableTreeObject, IdTreeObject):
"""Instantiate an Modeling Ply.
"""Instantiate a Modeling Ply.
Parameters
----------
name :
The name of the ModelingPly
The name of the Modeling Ply
ply_material :
The material (fabric, stackup or sub-laminate) of the ply.
ply_angle :
Expand All @@ -208,6 +208,8 @@ class ModelingPly(CreatableTreeObject, IdTreeObject):
draping_direction :
Set the primary draping direction for the draping algorithm. Only used if
``auto_draping_direction`` is ``False``.
use_default_draping_mesh_size :
Whether to use the average element size of the shell mesh for the draping.
draping_mesh_size :
Defines the mesh size for the draping algorithm. If set to ``-1.``, the
mesh size is automatically determined based on the average element size.
Expand Down Expand Up @@ -346,8 +348,8 @@ def _create_stub(self) -> modeling_ply_pb2_grpc.ObjectServiceStub:

selection_rules = define_edge_property_list("properties.selection_rules", LinkedSelectionRule)

production_plies = property(
get_read_only_collection_property(ProductionPly, production_ply_pb2_grpc.ObjectServiceStub)
production_plies = get_read_only_collection_property(
ProductionPly, production_ply_pb2_grpc.ObjectServiceStub
)

thickness_type = grpc_data_property(
Expand Down
4 changes: 2 additions & 2 deletions src/ansys/acp/core/_tree_objects/production_ply.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,6 @@ def _create_stub(self) -> production_ply_pb2_grpc.ObjectServiceStub:
elemental_data = elemental_data_property(ProductionPlyElementalData)
nodal_data = nodal_data_property(ProductionPlyNodalData)

analysis_plies = property(
get_read_only_collection_property(AnalysisPly, analysis_ply_pb2_grpc.ObjectServiceStub)
analysis_plies = get_read_only_collection_property(
AnalysisPly, analysis_ply_pb2_grpc.ObjectServiceStub
)

0 comments on commit 62ec7ae

Please sign in to comment.