From 0999d903e1b2fd91a902663e42855bf557154bfc Mon Sep 17 00:00:00 2001 From: moe-ad Date: Mon, 8 Dec 2025 10:52:43 +0100 Subject: [PATCH 01/27] feat: expose `PropertyFieldsContainer` class properly --- src/ansys/dpf/core/__init__.py | 1 + .../dpf/core/property_fields_container.py | 664 ++++++++++++------ src/ansys/dpf/gate/collection_grpcapi.py | 5 + 3 files changed, 460 insertions(+), 210 deletions(-) diff --git a/src/ansys/dpf/core/__init__.py b/src/ansys/dpf/core/__init__.py index df42d9d5109..1711c6be30b 100644 --- a/src/ansys/dpf/core/__init__.py +++ b/src/ansys/dpf/core/__init__.py @@ -39,6 +39,7 @@ from ansys.dpf.core.custom_type_field import CustomTypeField # noqa: F401 from ansys.dpf.core.dimensionality import Dimensionality from ansys.dpf.core.property_field import PropertyField +from ansys.dpf.core.property_fields_container import PropertyFieldsContainer from ansys.dpf.core.string_field import StringField from ansys.dpf.core.fields_container import FieldsContainer from ansys.dpf.core.meshes_container import MeshesContainer diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_container.py index 9d1f0a6f80e..a945629d85f 100644 --- a/src/ansys/dpf/core/property_fields_container.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -21,227 +21,471 @@ # SOFTWARE. """ -MockPropertyFieldsContainer. +PropertyFieldsContainer. -Contains classes associated with the _MockPropertyFieldsContainer. +Contains classes associated with the PropertyFieldsContainer. """ from __future__ import annotations -from collections.abc import Sequence -import copy +# from collections.abc import Sequence +# import copy from typing import Dict, List, Union -import numpy as np +# import numpy as np -import ansys.dpf.core as dpf +# import ansys.dpf.core as dpf from ansys.dpf.core import PropertyField -from ansys.dpf.core.server_types import BaseServer - - -class _LabelSpaceKV: - """Class for internal use to associate a label space with a field.""" - - def __init__(self, _dict: Dict[str, int], _field: dpf.Field): - """Construct an association between a dictionary and a field.""" - self._dict = _dict - self._field = _field - - @property - def dict(self) -> dict: - """Returns the associated dictionary.""" - return self._dict - - @property - def field(self) -> dpf.Field: - """Returns the associated field.""" - return self._field - - @field.setter - def field(self, value: dpf.Field): - self._field = value - - def __str__(self): - """Return a string representation of the association.""" - field_str = str(self._field).replace("\n", "\n\t\t\t") - return f"Label Space: {self._dict} with field\n\t\t\t{field_str}" - - -class _MockPropertyFieldsContainer(Sequence): - """Minimal implementation of a FieldsContainer specialized for _MockPropertyFieldsContainer.""" - - def __init__( - self, - fields_container: _MockPropertyFieldsContainer = None, - server: BaseServer = None, - ): - """Construct a _MockPropertyFieldsContainer.""" - # default constructor - self._labels = [] # used by Dataframe - self.scopings = [] - self._server = None # used by Dataframe - - self.label_spaces = [] - self.ids = [] - - # _MockPropertyFieldsContainer copy - if fields_container is not None: - self._labels = copy.deepcopy(fields_container.labels) - # self.scopings = copy.deepcopy(fields_container.scopings) - self._server = fields_container._server - - # self.ids = copy.deepcopy(fields_container.ids) - - for ls in fields_container.label_spaces: - self.add_entry(copy.deepcopy(ls.dict), ls.field.as_local_field()) - - # server copy - if server is not None: - self._server = server - - # Collection - def __str__(self) -> str: - """Return a string representation of a _MockPropertyFieldsContainer.""" - txt = f"DPF PropertyFieldsContainer with {len(self)} fields\n" - for idx, ls in enumerate(self.label_spaces): - txt += f"\t {idx}: {ls}\n" - - return txt - - @property - def labels(self) -> List[str]: - """Returns all labels of the _MockPropertyFieldsContainer.""" - return self._labels - - @labels.setter - def labels(self, labels: List[str]): - """Set all the label of the _MockPropertyFieldsContainer.""" - if len(self._labels) != 0: - raise ValueError("labels already set") - for l in labels: - self.add_label(l) - - def add_label(self, label: str): - """Add a label.""" - if label not in self._labels: - self._labels.append(label) - self.scopings.append([]) - - def has_label(self, label) -> bool: - """Check if a _MockPropertyFieldsContainer contains a given label.""" - return label in self.labels - - # used by Dataframe - def get_label_space(self, idx) -> Dict: - """Get a Label Space at a given index.""" - return self.label_spaces[idx].dict - - # used by Dataframe - def get_label_scoping(self, label="time") -> dpf.Scoping: - """Return a scoping on the fields concerned by the given label.""" - if label in self.labels: - scoping_ids = self.scopings[self.labels.index(label)] - return dpf.Scoping(ids=scoping_ids, location="") - raise KeyError(f"label {label} not found") - - def add_entry(self, label_space: Dict[str, int], value: dpf.Field): - """Add a PropertyField associated with a dictionary.""" - new_id = self._new_id() - - if hasattr(value, "_server"): - self._server = value._server - - # add Label Space - self.label_spaces.append(_LabelSpaceKV(label_space, value)) - - # Update IDs - self.ids.append(new_id) - - # Update Scopings - for label in label_space.keys(): - label_idx = self.labels.index(label) - self.scopings[label_idx].append(new_id) - - def add_field(self, label_space: Dict[str, int], field: dpf.Field): - """Add or update a field at a requested label space.""" - self.add_entry(label_space, field) - - def get_entries(self, label_space_or_index: Union[Dict[str, int], int]): - """Return a list of fields from a complete or partial specification of a dictionary.""" - if isinstance(label_space_or_index, int): - idx: int = label_space_or_index - return [self.label_spaces[idx].field] - else: - _dict: Dict[str, int] = label_space_or_index - are_keys_in_labels = [key in self.labels for key in _dict.keys()] - if all(are_keys_in_labels): - remaining = set(range(len(self.label_spaces))) - for key in _dict.keys(): - val = _dict[key] - to_remove = set() - for idx in remaining: - ls = self.label_spaces[idx] - if key in ls.dict.keys(): - if ls.dict[key] != val: - to_remove.add(idx) - else: - to_remove.add(idx) - remaining = remaining.difference(to_remove) - - idx_to_field = lambda idx: self.label_spaces[idx].field - return list(map(idx_to_field, remaining)) +from ansys.dpf.core.collection_base import CollectionBase +# from ansys.dpf.core.server_types import BaseServer + + +# class _LabelSpaceKV: +# """Class for internal use to associate a label space with a field.""" + +# def __init__(self, _dict: Dict[str, int], _field: dpf.Field): +# """Construct an association between a dictionary and a field.""" +# self._dict = _dict +# self._field = _field + +# @property +# def dict(self) -> dict: +# """Returns the associated dictionary.""" +# return self._dict + +# @property +# def field(self) -> dpf.Field: +# """Returns the associated field.""" +# return self._field + +# @field.setter +# def field(self, value: dpf.Field): +# self._field = value + +# def __str__(self): +# """Return a string representation of the association.""" +# field_str = str(self._field).replace("\n", "\n\t\t\t") +# return f"Label Space: {self._dict} with field\n\t\t\t{field_str}" + + +class PropertyFieldsContainer(CollectionBase[PropertyField]): + """Represents a property fields container, which contains property fields. + + A property fields container is a set of property fields ordered by labels and IDs. + Each property field in the container has an ID for each label, allowing flexible + organization and retrieval of property fields based on various criteria. + + Parameters + ---------- + property_fields_container : ansys.grpc.dpf.collection_message_pb2.Collection, ctypes.c_void_p, + PropertyFieldsContainer, optional + Property fields container created from either a collection message or by copying + an existing one. The default is ``None``. + server : ansys.dpf.core.server, optional + Server with the channel connected to the remote or local instance. + The default is ``None``, in which case an attempt is made to use the global + server. + + Examples + -------- + Create a property fields container from scratch. + + >>> from ansys.dpf import core as dpf + >>> pfc = dpf.PropertyFieldsContainer() + >>> pfc.labels = ['time', 'body'] + >>> for i in range(0, 5): + ... label_space = {"time": i+1, "body": 0} + ... pfield = dpf.PropertyField() + ... pfield.data = list(range(i*10, (i+1)*10)) + ... pfc.add_field(label_space, pfield) + + """ + + entries_type = PropertyField + + def __init__(self, property_fields_container=None, server=None): + """Initialize a property fields container.""" + super().__init__(collection=property_fields_container, server=server) + if self._internal_obj is None: + # PropertyField collections use the generic custom_type_field collection + if self._server.has_client(): + self._internal_obj = self._api.collection_of_custom_type_field_new_on_client( + self._server.client + ) else: - bad_idx = are_keys_in_labels.index(False) - bad_key = list(_dict.keys())[bad_idx] - raise KeyError(f"Key {bad_key} is not in labels: {self.labels}") - - def get_entry(self, label_space_or_index: Union[Dict[str, int], int]): - """Return the field or (first field found) corresponding to the given dictionary.""" - ret = self.get_entries(label_space_or_index) - - if len(ret) != 0: - return ret[0] - - raise ValueError("Could not find corresponding entry") - - def _new_id(self) -> int: - """Helper-method generating a new id when calling add_entry(...).""" - if len(self.ids) == 0: - self.last_id = 1 - return self.last_id - else: - self.last_id += 1 - return self.last_id - - # used by Dataframe - def get_fields(self, label_space: Dict[str, int]) -> List[dpf.Field]: - """Return the list of fields associated with given label space.""" + self._internal_obj = self._api.collection_of_custom_type_field_new() + + def create_subtype(self, obj_by_copy): + """Create a property field subtype.""" + return PropertyField(property_field=obj_by_copy, server=self._server) + + def get_fields(self, label_space: Dict[str, int]) -> List[PropertyField]: + """Retrieve the property fields at a requested label space. + + Parameters + ---------- + label_space : dict[str, int] + Scoping of the requested property fields. For example, + ``{"time": 1, "body": 0}``. + + Returns + ------- + fields : list[PropertyField] + Property fields corresponding to the request. + + Examples + -------- + >>> from ansys.dpf import core as dpf + >>> pfc = dpf.PropertyFieldsContainer() + >>> pfc.labels = ['time'] + >>> # ... add property fields ... + >>> fields = pfc.get_fields({"time": 1}) + + """ return self.get_entries(label_space) - def get_field(self, label_space_or_index: Union[Dict[str, int], int]) -> dpf.Field: - """Retrieve the field at a requested index or label space.""" + def get_field(self, label_space_or_index: Union[Dict[str, int], int]) -> PropertyField: + """Retrieve the property field at a requested index or label space. + + An exception is raised if the number of property fields matching the request + is greater than one. + + Parameters + ---------- + label_space_or_index : dict[str, int], int + Scoping of the requested property field, for example, + ``{"time": 1, "body": 0}``, or index of the property field. + + Returns + ------- + field : PropertyField + Property field corresponding to the request. + + Examples + -------- + >>> from ansys.dpf import core as dpf + >>> pfc = dpf.PropertyFieldsContainer() + >>> pfc.labels = ['time'] + >>> # ... add property fields ... + >>> field = pfc.get_field({"time": 1}) + >>> # Or by index + >>> field = pfc.get_field(0) + + """ return self.get_entry(label_space_or_index) - # used by Dataframe - def __getitem__(self, key: Union[Dict[str, int], int]) -> dpf.Field: - """Retrieve the field at a requested index.""" - return self.get_field(key) - - def __len__(self) -> int: - """Retrieve the number of label spaces.""" - return len(self.label_spaces) - - def _set_field(self, ls_idx, field): - self.label_spaces[ls_idx].field = field - - def rescope(self, scoping: dpf.Scoping): # Used by post.Dataframe - """Helper-function to reproduce functionality of rescope_fc Operator.""" - copy_fc = _MockPropertyFieldsContainer(self, server=None) - for idx, label_space in enumerate(copy_fc.label_spaces): - pfield = PropertyField(location=label_space.field.location) - pfield.data = np.ravel( - [label_space._field.get_entity_data_by_id(id) for id in scoping.ids] - ) - pfield.scoping.ids = scoping.ids - copy_fc._set_field(idx, pfield) - return copy_fc + def add_field(self, label_space: Dict[str, int], field: PropertyField): + """Add or update a property field at a requested label space. + + Parameters + ---------- + label_space : dict[str, int] + Label space of the requested property field. For example, + ``{"time": 1, "body": 0}``. + field : PropertyField + DPF property field to add or update. + + Examples + -------- + >>> from ansys.dpf import core as dpf + >>> pfc = dpf.PropertyFieldsContainer() + >>> pfc.labels = ['time'] + >>> pfield = dpf.PropertyField() + >>> pfield.data = [1, 2, 3, 4, 5] + >>> pfc.add_field({"time": 1}, pfield) + + """ + self.add_entry(label_space, field) + + def add_entry(self, label_space: Dict[str, int], field: PropertyField): + """Add or update a property field entry at a requested label space. + + This method is an alias for :func:`add_field()` to maintain API compatibility + with _MockPropertyFieldsContainer. + + Parameters + ---------- + label_space : dict[str, int] + Label space of the requested property field. For example, + ``{"time": 1, "body": 0}``. + field : PropertyField + DPF property field to add or update. + + Examples + -------- + >>> from ansys.dpf import core as dpf + >>> pfc = dpf.PropertyFieldsContainer() + >>> pfc.labels = ['time'] + >>> pfield = dpf.PropertyField() + >>> pfield.data = [1, 2, 3, 4, 5] + >>> pfc.add_entry({"time": 1}, pfield) + + """ + super()._add_entry(label_space, field) + + def get_entries(self, label_space: Dict[str, int]) -> List[PropertyField]: + """Retrieve the property fields at a requested index or label space. + + This method returns a list of property fields. For partial label space queries, + it may return multiple fields. For index queries, it returns a single-element list. + + Parameters + ---------- + label_space_or_index : dict[str, int], int + Scoping of the requested property fields, for example, + ``{"time": 1}``, or index of the property field. + + Returns + ------- + fields : list[PropertyField] + Property fields corresponding to the request. + + Examples + -------- + >>> from ansys.dpf import core as dpf + >>> pfc = dpf.PropertyFieldsContainer() + >>> pfc.labels = ['time', 'complex'] + >>> # ... add property fields ... + >>> # Get all fields at time=1 (may return multiple if complex varies) + >>> fields = pfc.get_entries({"time": 1}) + >>> # Get field at index 0 (returns single-element list) + >>> fields = pfc.get_entries(0) + + """ + return super()._get_entries(label_space) + + def get_entry(self, label_space_or_index: Union[Dict[str, int], int]) -> PropertyField: + """Retrieve a single property field at a requested index or label space. + + This method is an alias for :func:`get_field()` to maintain API compatibility + with _MockPropertyFieldsContainer. An exception is raised if the number of + property fields matching the request is greater than one. + + Parameters + ---------- + label_space_or_index : dict[str, int], int + Scoping of the requested property field, for example, + ``{"time": 1, "body": 0}``, or index of the property field. + + Returns + ------- + field : PropertyField + Property field corresponding to the request. + + Examples + -------- + >>> from ansys.dpf import core as dpf + >>> pfc = dpf.PropertyFieldsContainer() + >>> pfc.labels = ['time'] + >>> # ... add property fields ... + >>> field = pfc.get_entry({"time": 1}) + >>> # Or by index + >>> field = pfc.get_entry(0) + + """ + return super()._get_entry(label_space_or_index) + + def __getitem__(self, key: Union[int, Dict[str, int]]) -> PropertyField: + """Retrieve the property field at a requested index or label space. + + Parameters + ---------- + key : int, dict[str, int] + Index or label space. + + Returns + ------- + field : PropertyField + Property field corresponding to the request. + + Examples + -------- + >>> from ansys.dpf import core as dpf + >>> pfc = dpf.PropertyFieldsContainer() + >>> pfc.labels = ['time'] + >>> # ... add property fields ... + >>> field = pfc[0] # Access by index + >>> field = pfc[{"time": 1}] # Access by label space + + """ + return super().__getitem__(key) + + +# class _MockPropertyFieldsContainer(Sequence): +# """Minimal implementation of a FieldsContainer specialized for _MockPropertyFieldsContainer.""" + +# def __init__( +# self, +# fields_container: _MockPropertyFieldsContainer = None, +# server: BaseServer = None, +# ): +# """Construct a _MockPropertyFieldsContainer.""" +# # default constructor +# self._labels = [] # used by Dataframe +# self.scopings = [] +# self._server = None # used by Dataframe + +# self.label_spaces = [] +# self.ids = [] + +# # _MockPropertyFieldsContainer copy +# if fields_container is not None: +# self._labels = copy.deepcopy(fields_container.labels) +# # self.scopings = copy.deepcopy(fields_container.scopings) +# self._server = fields_container._server + +# # self.ids = copy.deepcopy(fields_container.ids) + +# for ls in fields_container.label_spaces: +# self.add_entry(copy.deepcopy(ls.dict), ls.field.as_local_field()) + +# # server copy +# if server is not None: +# self._server = server + +# # Collection +# def __str__(self) -> str: # Exposed in CollectionBase +# """Return a string representation of a _MockPropertyFieldsContainer.""" +# txt = f"DPF PropertyFieldsContainer with {len(self)} fields\n" +# for idx, ls in enumerate(self.label_spaces): +# txt += f"\t {idx}: {ls}\n" + +# return txt + +# @property +# def labels(self) -> List[str]: # Possible through __get_labels in CollectionBase +# """Returns all labels of the _MockPropertyFieldsContainer.""" +# return self._labels + +# @labels.setter # Possible through set_labels in CollectionBase +# def labels(self, labels: List[str]): +# """Set all the label of the _MockPropertyFieldsContainer.""" +# if len(self._labels) != 0: +# raise ValueError("labels already set") +# for l in labels: +# self.add_label(l) + +# def add_label(self, label: str): # Exposed in CollectionBase +# """Add a label.""" +# if label not in self._labels: +# self._labels.append(label) +# self.scopings.append([]) + +# def has_label(self, label) -> bool: # Exposed in CollectionBase +# """Check if a _MockPropertyFieldsContainer contains a given label.""" +# return label in self.labels + +# # used by Dataframe +# def get_label_space(self, idx) -> Dict: # Exposed in CollectionBase +# """Get a Label Space at a given index.""" +# return self.label_spaces[idx].dict + +# # used by Dataframe +# def get_label_scoping(self, label="time") -> dpf.Scoping: # Exposed in CollectionBase +# """Return a scoping on the fields concerned by the given label.""" +# if label in self.labels: +# scoping_ids = self.scopings[self.labels.index(label)] +# return dpf.Scoping(ids=scoping_ids, location="") +# raise KeyError(f"label {label} not found") + +# def add_entry(self, label_space: Dict[str, int], value: dpf.Field): # Exposed in CollectionBase +# """Add a PropertyField associated with a dictionary.""" +# new_id = self._new_id() + +# if hasattr(value, "_server"): +# self._server = value._server + +# # add Label Space +# self.label_spaces.append(_LabelSpaceKV(label_space, value)) + +# # Update IDs +# self.ids.append(new_id) + +# # Update Scopings +# for label in label_space.keys(): +# label_idx = self.labels.index(label) +# self.scopings[label_idx].append(new_id) + +# def add_field(self, label_space: Dict[str, int], field: dpf.Field): # Exposed in CollectionBase (indirectly through _add_entry) +# """Add or update a field at a requested label space.""" +# self.add_entry(label_space, field) + +# def get_entries(self, label_space_or_index: Union[Dict[str, int], int]): # Exposed in CollectionBase +# """Return a list of fields from a complete or partial specification of a dictionary.""" +# if isinstance(label_space_or_index, int): +# idx: int = label_space_or_index +# return [self.label_spaces[idx].field] +# else: +# _dict: Dict[str, int] = label_space_or_index +# are_keys_in_labels = [key in self.labels for key in _dict.keys()] +# if all(are_keys_in_labels): +# remaining = set(range(len(self.label_spaces))) +# for key in _dict.keys(): +# val = _dict[key] +# to_remove = set() +# for idx in remaining: +# ls = self.label_spaces[idx] +# if key in ls.dict.keys(): +# if ls.dict[key] != val: +# to_remove.add(idx) +# else: +# to_remove.add(idx) +# remaining = remaining.difference(to_remove) + +# idx_to_field = lambda idx: self.label_spaces[idx].field +# return list(map(idx_to_field, remaining)) +# else: +# bad_idx = are_keys_in_labels.index(False) +# bad_key = list(_dict.keys())[bad_idx] +# raise KeyError(f"Key {bad_key} is not in labels: {self.labels}") + +# def get_entry(self, label_space_or_index: Union[Dict[str, int], int]): # Exposed in CollectionBase +# """Return the field or (first field found) corresponding to the given dictionary.""" +# ret = self.get_entries(label_space_or_index) + +# if len(ret) != 0: +# return ret[0] + +# raise ValueError("Could not find corresponding entry") + +# def _new_id(self) -> int: # Will no longer be needed +# """Helper-method generating a new id when calling add_entry(...).""" +# if len(self.ids) == 0: +# self.last_id = 1 +# return self.last_id +# else: +# self.last_id += 1 +# return self.last_id + +# # used by Dataframe +# def get_fields(self, label_space: Dict[str, int]) -> List[dpf.Field]: # Exposed in CollectionBase (indirectly through _get_entries) +# """Return the list of fields associated with given label space.""" +# return self.get_entries(label_space) + +# def get_field(self, label_space_or_index: Union[Dict[str, int], int]) -> dpf.Field: # Exposed in CollectionBase (indirectly through _get_entry) +# """Retrieve the field at a requested index or label space.""" +# return self.get_entry(label_space_or_index) + +# # used by Dataframe +# def __getitem__(self, key: Union[Dict[str, int], int]) -> dpf.Field: # Exposed in CollectionBase +# """Retrieve the field at a requested index.""" +# return self.get_field(key) + +# def __len__(self) -> int: # Exposed in CollectionBase +# """Retrieve the number of label spaces.""" +# return len(self.label_spaces) + +# def _set_field(self, ls_idx, field): +# self.label_spaces[ls_idx].field = field + +# def rescope(self, scoping: dpf.Scoping): # Used by post.Dataframe +# """Helper-function to reproduce functionality of rescope_fc Operator.""" +# copy_fc = _MockPropertyFieldsContainer(self, server=None) +# for idx, label_space in enumerate(copy_fc.label_spaces): +# pfield = PropertyField(location=label_space.field.location) +# pfield.data = np.ravel( +# [label_space._field.get_entity_data_by_id(id) for id in scoping.ids] +# ) +# pfield.scoping.ids = scoping.ids +# copy_fc._set_field(idx, pfield) +# return copy_fc diff --git a/src/ansys/dpf/gate/collection_grpcapi.py b/src/ansys/dpf/gate/collection_grpcapi.py index ed94af7e2d5..8ba60d95f4c 100644 --- a/src/ansys/dpf/gate/collection_grpcapi.py +++ b/src/ansys/dpf/gate/collection_grpcapi.py @@ -76,6 +76,11 @@ def collection_of_any_new_on_client(client): from ansys.grpc.dpf import base_pb2 return CollectionGRPCAPI.collection_new_on_client(client, base_pb2.Type.Value("ANY")) + @staticmethod + def collection_of_custom_type_field_new_on_client(client): + from ansys.grpc.dpf import base_pb2 + return CollectionGRPCAPI.collection_new_on_client(client, base_pb2.Type.Value("PROPERTY_FIELD")) + @staticmethod def collection_add_label(collection, label): from ansys.grpc.dpf import collection_pb2 From 4305e7ee2da39df677068c448be0b6734ff33f3e Mon Sep 17 00:00:00 2001 From: moe-ad Date: Mon, 8 Dec 2025 10:56:50 +0100 Subject: [PATCH 02/27] test: comment out new grpc method --- src/ansys/dpf/gate/collection_grpcapi.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ansys/dpf/gate/collection_grpcapi.py b/src/ansys/dpf/gate/collection_grpcapi.py index 8ba60d95f4c..3705e6e6c4b 100644 --- a/src/ansys/dpf/gate/collection_grpcapi.py +++ b/src/ansys/dpf/gate/collection_grpcapi.py @@ -76,10 +76,10 @@ def collection_of_any_new_on_client(client): from ansys.grpc.dpf import base_pb2 return CollectionGRPCAPI.collection_new_on_client(client, base_pb2.Type.Value("ANY")) - @staticmethod - def collection_of_custom_type_field_new_on_client(client): - from ansys.grpc.dpf import base_pb2 - return CollectionGRPCAPI.collection_new_on_client(client, base_pb2.Type.Value("PROPERTY_FIELD")) + # @staticmethod + # def collection_of_property_field_new_on_client(client): + # from ansys.grpc.dpf import base_pb2 + # return CollectionGRPCAPI.collection_new_on_client(client, base_pb2.Type.Value("PROPERTY_FIELD")) @staticmethod def collection_add_label(collection, label): From 1cafee0c4a38de2c5e350e3d3e22a9b0bf4d3098 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Mon, 8 Dec 2025 11:00:30 +0100 Subject: [PATCH 03/27] test: reorder --- .../dpf/core/property_fields_container.py | 57 ++++++++++--------- 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_container.py index a945629d85f..91d226167bf 100644 --- a/src/ansys/dpf/core/property_fields_container.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -40,34 +40,6 @@ # from ansys.dpf.core.server_types import BaseServer -# class _LabelSpaceKV: -# """Class for internal use to associate a label space with a field.""" - -# def __init__(self, _dict: Dict[str, int], _field: dpf.Field): -# """Construct an association between a dictionary and a field.""" -# self._dict = _dict -# self._field = _field - -# @property -# def dict(self) -> dict: -# """Returns the associated dictionary.""" -# return self._dict - -# @property -# def field(self) -> dpf.Field: -# """Returns the associated field.""" -# return self._field - -# @field.setter -# def field(self, value: dpf.Field): -# self._field = value - -# def __str__(self): -# """Return a string representation of the association.""" -# field_str = str(self._field).replace("\n", "\n\t\t\t") -# return f"Label Space: {self._dict} with field\n\t\t\t{field_str}" - - class PropertyFieldsContainer(CollectionBase[PropertyField]): """Represents a property fields container, which contains property fields. @@ -311,6 +283,35 @@ def __getitem__(self, key: Union[int, Dict[str, int]]) -> PropertyField: return super().__getitem__(key) +# class _LabelSpaceKV: +# """Class for internal use to associate a label space with a field.""" + +# def __init__(self, _dict: Dict[str, int], _field: dpf.Field): +# """Construct an association between a dictionary and a field.""" +# self._dict = _dict +# self._field = _field + +# @property +# def dict(self) -> dict: +# """Returns the associated dictionary.""" +# return self._dict + +# @property +# def field(self) -> dpf.Field: +# """Returns the associated field.""" +# return self._field + +# @field.setter +# def field(self, value: dpf.Field): +# self._field = value + +# def __str__(self): +# """Return a string representation of the association.""" +# field_str = str(self._field).replace("\n", "\n\t\t\t") +# return f"Label Space: {self._dict} with field\n\t\t\t{field_str}" + + + # class _MockPropertyFieldsContainer(Sequence): # """Minimal implementation of a FieldsContainer specialized for _MockPropertyFieldsContainer.""" From 5fe6649e6d6c65fcfe5b522d6e689a08781d3915 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Mon, 8 Dec 2025 12:59:59 +0100 Subject: [PATCH 04/27] feat: implement review suggestion and add tests --- src/ansys/dpf/core/__init__.py | 2 +- .../dpf/core/property_fields_container.py | 241 +----------------- src/ansys/dpf/gate/collection_grpcapi.py | 5 - tests/test_property_fields_container.py | 183 ++++++++++--- 4 files changed, 161 insertions(+), 270 deletions(-) diff --git a/src/ansys/dpf/core/__init__.py b/src/ansys/dpf/core/__init__.py index 1711c6be30b..45edada1984 100644 --- a/src/ansys/dpf/core/__init__.py +++ b/src/ansys/dpf/core/__init__.py @@ -39,7 +39,7 @@ from ansys.dpf.core.custom_type_field import CustomTypeField # noqa: F401 from ansys.dpf.core.dimensionality import Dimensionality from ansys.dpf.core.property_field import PropertyField -from ansys.dpf.core.property_fields_container import PropertyFieldsContainer +from ansys.dpf.core.property_fields_container import PropertyFieldsCollection from ansys.dpf.core.string_field import StringField from ansys.dpf.core.fields_container import FieldsContainer from ansys.dpf.core.meshes_container import MeshesContainer diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_container.py index 91d226167bf..a2908b3e2d6 100644 --- a/src/ansys/dpf/core/property_fields_container.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -21,37 +21,29 @@ # SOFTWARE. """ -PropertyFieldsContainer. +PropertyFieldsCollection. -Contains classes associated with the PropertyFieldsContainer. +Contains classes associated with the PropertyFieldsCollection. """ from __future__ import annotations -# from collections.abc import Sequence -# import copy -from typing import Dict, List, Union - -# import numpy as np - -# import ansys.dpf.core as dpf from ansys.dpf.core import PropertyField -from ansys.dpf.core.collection_base import CollectionBase -# from ansys.dpf.core.server_types import BaseServer +from ansys.dpf.core.collection import Collection -class PropertyFieldsContainer(CollectionBase[PropertyField]): - """Represents a property fields container, which contains property fields. +class PropertyFieldsCollection(Collection[PropertyField]): + """Represents a property fields collection, which contains property fields. - A property fields container is a set of property fields ordered by labels and IDs. - Each property field in the container has an ID for each label, allowing flexible + A property fields collection is a set of property fields ordered by labels and IDs. + Each property field in the collection has an ID for each label, allowing flexible organization and retrieval of property fields based on various criteria. Parameters ---------- - property_fields_container : ansys.grpc.dpf.collection_message_pb2.Collection, ctypes.c_void_p, - PropertyFieldsContainer, optional - Property fields container created from either a collection message or by copying + property_fields_collection : ansys.grpc.dpf.collection_message_pb2.Collection, ctypes.c_void_p, + PropertyFieldsCollection, optional + Property fields collection created from either a collection message or by copying an existing one. The default is ``None``. server : ansys.dpf.core.server, optional Server with the channel connected to the remote or local instance. @@ -60,10 +52,10 @@ class PropertyFieldsContainer(CollectionBase[PropertyField]): Examples -------- - Create a property fields container from scratch. + Create a property fields collection from scratch. >>> from ansys.dpf import core as dpf - >>> pfc = dpf.PropertyFieldsContainer() + >>> pfc = dpf.PropertyFieldsCollection() >>> pfc.labels = ['time', 'body'] >>> for i in range(0, 5): ... label_space = {"time": i+1, "body": 0} @@ -73,214 +65,9 @@ class PropertyFieldsContainer(CollectionBase[PropertyField]): """ - entries_type = PropertyField - - def __init__(self, property_fields_container=None, server=None): + def __init__(self, property_fields_collection=None, server=None, entries_type: type = PropertyField): """Initialize a property fields container.""" - super().__init__(collection=property_fields_container, server=server) - if self._internal_obj is None: - # PropertyField collections use the generic custom_type_field collection - if self._server.has_client(): - self._internal_obj = self._api.collection_of_custom_type_field_new_on_client( - self._server.client - ) - else: - self._internal_obj = self._api.collection_of_custom_type_field_new() - - def create_subtype(self, obj_by_copy): - """Create a property field subtype.""" - return PropertyField(property_field=obj_by_copy, server=self._server) - - def get_fields(self, label_space: Dict[str, int]) -> List[PropertyField]: - """Retrieve the property fields at a requested label space. - - Parameters - ---------- - label_space : dict[str, int] - Scoping of the requested property fields. For example, - ``{"time": 1, "body": 0}``. - - Returns - ------- - fields : list[PropertyField] - Property fields corresponding to the request. - - Examples - -------- - >>> from ansys.dpf import core as dpf - >>> pfc = dpf.PropertyFieldsContainer() - >>> pfc.labels = ['time'] - >>> # ... add property fields ... - >>> fields = pfc.get_fields({"time": 1}) - - """ - return self.get_entries(label_space) - - def get_field(self, label_space_or_index: Union[Dict[str, int], int]) -> PropertyField: - """Retrieve the property field at a requested index or label space. - - An exception is raised if the number of property fields matching the request - is greater than one. - - Parameters - ---------- - label_space_or_index : dict[str, int], int - Scoping of the requested property field, for example, - ``{"time": 1, "body": 0}``, or index of the property field. - - Returns - ------- - field : PropertyField - Property field corresponding to the request. - - Examples - -------- - >>> from ansys.dpf import core as dpf - >>> pfc = dpf.PropertyFieldsContainer() - >>> pfc.labels = ['time'] - >>> # ... add property fields ... - >>> field = pfc.get_field({"time": 1}) - >>> # Or by index - >>> field = pfc.get_field(0) - - """ - return self.get_entry(label_space_or_index) - - def add_field(self, label_space: Dict[str, int], field: PropertyField): - """Add or update a property field at a requested label space. - - Parameters - ---------- - label_space : dict[str, int] - Label space of the requested property field. For example, - ``{"time": 1, "body": 0}``. - field : PropertyField - DPF property field to add or update. - - Examples - -------- - >>> from ansys.dpf import core as dpf - >>> pfc = dpf.PropertyFieldsContainer() - >>> pfc.labels = ['time'] - >>> pfield = dpf.PropertyField() - >>> pfield.data = [1, 2, 3, 4, 5] - >>> pfc.add_field({"time": 1}, pfield) - - """ - self.add_entry(label_space, field) - - def add_entry(self, label_space: Dict[str, int], field: PropertyField): - """Add or update a property field entry at a requested label space. - - This method is an alias for :func:`add_field()` to maintain API compatibility - with _MockPropertyFieldsContainer. - - Parameters - ---------- - label_space : dict[str, int] - Label space of the requested property field. For example, - ``{"time": 1, "body": 0}``. - field : PropertyField - DPF property field to add or update. - - Examples - -------- - >>> from ansys.dpf import core as dpf - >>> pfc = dpf.PropertyFieldsContainer() - >>> pfc.labels = ['time'] - >>> pfield = dpf.PropertyField() - >>> pfield.data = [1, 2, 3, 4, 5] - >>> pfc.add_entry({"time": 1}, pfield) - - """ - super()._add_entry(label_space, field) - - def get_entries(self, label_space: Dict[str, int]) -> List[PropertyField]: - """Retrieve the property fields at a requested index or label space. - - This method returns a list of property fields. For partial label space queries, - it may return multiple fields. For index queries, it returns a single-element list. - - Parameters - ---------- - label_space_or_index : dict[str, int], int - Scoping of the requested property fields, for example, - ``{"time": 1}``, or index of the property field. - - Returns - ------- - fields : list[PropertyField] - Property fields corresponding to the request. - - Examples - -------- - >>> from ansys.dpf import core as dpf - >>> pfc = dpf.PropertyFieldsContainer() - >>> pfc.labels = ['time', 'complex'] - >>> # ... add property fields ... - >>> # Get all fields at time=1 (may return multiple if complex varies) - >>> fields = pfc.get_entries({"time": 1}) - >>> # Get field at index 0 (returns single-element list) - >>> fields = pfc.get_entries(0) - - """ - return super()._get_entries(label_space) - - def get_entry(self, label_space_or_index: Union[Dict[str, int], int]) -> PropertyField: - """Retrieve a single property field at a requested index or label space. - - This method is an alias for :func:`get_field()` to maintain API compatibility - with _MockPropertyFieldsContainer. An exception is raised if the number of - property fields matching the request is greater than one. - - Parameters - ---------- - label_space_or_index : dict[str, int], int - Scoping of the requested property field, for example, - ``{"time": 1, "body": 0}``, or index of the property field. - - Returns - ------- - field : PropertyField - Property field corresponding to the request. - - Examples - -------- - >>> from ansys.dpf import core as dpf - >>> pfc = dpf.PropertyFieldsContainer() - >>> pfc.labels = ['time'] - >>> # ... add property fields ... - >>> field = pfc.get_entry({"time": 1}) - >>> # Or by index - >>> field = pfc.get_entry(0) - - """ - return super()._get_entry(label_space_or_index) - - def __getitem__(self, key: Union[int, Dict[str, int]]) -> PropertyField: - """Retrieve the property field at a requested index or label space. - - Parameters - ---------- - key : int, dict[str, int] - Index or label space. - - Returns - ------- - field : PropertyField - Property field corresponding to the request. - - Examples - -------- - >>> from ansys.dpf import core as dpf - >>> pfc = dpf.PropertyFieldsContainer() - >>> pfc.labels = ['time'] - >>> # ... add property fields ... - >>> field = pfc[0] # Access by index - >>> field = pfc[{"time": 1}] # Access by label space - - """ - return super().__getitem__(key) + super().__init__(collection=property_fields_collection, server=server, entries_type=entries_type) # class _LabelSpaceKV: diff --git a/src/ansys/dpf/gate/collection_grpcapi.py b/src/ansys/dpf/gate/collection_grpcapi.py index 3705e6e6c4b..ed94af7e2d5 100644 --- a/src/ansys/dpf/gate/collection_grpcapi.py +++ b/src/ansys/dpf/gate/collection_grpcapi.py @@ -76,11 +76,6 @@ def collection_of_any_new_on_client(client): from ansys.grpc.dpf import base_pb2 return CollectionGRPCAPI.collection_new_on_client(client, base_pb2.Type.Value("ANY")) - # @staticmethod - # def collection_of_property_field_new_on_client(client): - # from ansys.grpc.dpf import base_pb2 - # return CollectionGRPCAPI.collection_new_on_client(client, base_pb2.Type.Value("PROPERTY_FIELD")) - @staticmethod def collection_add_label(collection, label): from ansys.grpc.dpf import collection_pb2 diff --git a/tests/test_property_fields_container.py b/tests/test_property_fields_container.py index 5c8525b4aa6..ddbcc209af6 100644 --- a/tests/test_property_fields_container.py +++ b/tests/test_property_fields_container.py @@ -23,47 +23,156 @@ import pytest from ansys.dpf import core as dpf -from ansys.dpf.core.property_fields_container import _LabelSpaceKV, _MockPropertyFieldsContainer +from ansys.dpf.core.property_fields_container import PropertyFieldsCollection -def test_property_fields_container(allkindofcomplexity, server_type): +def test_property_fields_collection(allkindofcomplexity, server_type): + """Test PropertyFieldsCollection class.""" model = dpf.Model(allkindofcomplexity, server=server_type) - fields_container = _MockPropertyFieldsContainer(server=server_type) - fields_container.add_label(label="test") - assert fields_container.has_label(label="test") - assert fields_container.labels == ["test"] - with pytest.raises(ValueError, match="labels already set"): - fields_container.labels = ["test"] - field = model.metadata.meshed_region.elements.connectivities_field - fields_container.add_field(label_space={"test": 42}, field=field) - assert len(fields_container.label_spaces) == 1 - label_space = fields_container.label_spaces[0] - assert fields_container.get_label_space(0) == {"test": 42} - assert isinstance(label_space, _LabelSpaceKV) - assert label_space.field == field - assert label_space.dict == {"test": 42} - label_space.field = model.metadata.meshed_region.elements.element_types_field - ref = """DPF PropertyFieldsContainer with 1 fields -\t 0: Label Space: {'test': 42} with field -\t\t\t""" # noqa - assert ref in str(fields_container) + + # Create a PropertyFieldsCollection + pfc = PropertyFieldsCollection(server=server_type) + + # Test adding labels + pfc.add_label(label="test") + assert pfc.has_label(label="test") + assert pfc.labels == ["test"] + + # Test adding another label + pfc.add_label(label="body") + assert pfc.has_label(label="body") + assert pfc.labels == ["test", "body"] + + # Get a property field from the model + property_field = model.metadata.meshed_region.elements.connectivities_field + + # Test add_entry method + pfc.add_entry(label_space={"test": 42, "body": 0}, entry=property_field) + assert len(pfc) == 1 + + # Test get_label_space + label_space = pfc.get_label_space(0) + assert label_space == {"test": 42, "body": 0} + + # Test get_label_scoping with pytest.raises(KeyError, match="label test2 not found"): - fields_container.get_label_scoping("test2") - scoping = fields_container.get_label_scoping("test") + pfc.get_label_scoping("test2") + + scoping = pfc.get_label_scoping("test") assert isinstance(scoping, dpf.Scoping) - assert scoping.ids == [1] - assert scoping.location == "" + assert 42 in scoping.ids + + # Test get_entries with label space + entries = pfc.get_entries({"test": 42, "body": 0}) + assert len(entries) >= 1 + retrieved_field = entries[0] + assert isinstance(retrieved_field, dpf.PropertyField) + + # Test get_entry with label space + entry = pfc.get_entry({"test": 42, "body": 0}) + assert isinstance(entry, dpf.PropertyField) + + # Test get_entry with index + entry_by_index = pfc.get_entry(0) + assert isinstance(entry_by_index, dpf.PropertyField) + + # Test __getitem__ with index + field_by_index = pfc[0] + assert isinstance(field_by_index, dpf.PropertyField) + + # Test __getitem__ with label space + field_by_label = pfc[{"test": 42, "body": 0}] + assert isinstance(field_by_label, dpf.PropertyField) + + # Test adding more entries with different label spaces + property_field2 = model.metadata.meshed_region.elements.element_types_field + pfc.add_entry(label_space={"test": 43, "body": 0}, entry=property_field2) + assert len(pfc) == 2 + + # Test retrieving multiple entries with partial label space + entries_body0 = pfc.get_entries({"body": 0}) + assert len(entries_body0) == 2 + + # Test get_available_ids_for_label + test_ids = pfc.get_available_ids_for_label("test") + assert 42 in test_ids + assert 43 in test_ids - property_field = fields_container.get_entries(0)[0] - assert isinstance(property_field, dpf.property_field.PropertyField) - assert fields_container.get_entries({"test": 42})[0] == property_field - with pytest.raises(KeyError, match="is not in labels:"): - fields_container.get_entries(({"test2": 0})) - assert fields_container.get_entry({"test": 42}) == property_field - with pytest.raises(ValueError, match="Could not find corresponding entry"): - fields_container.get_entry(({"test": 0})) - assert fields_container[{"test": 42}] == property_field - assert len(fields_container) == 1 - assert fields_container.get_fields({"test": 42})[0] == property_field - assert fields_container.get_field(0) == property_field +def test_property_fields_collection_from_scratch(server_type): + """Test creating PropertyFieldsCollection from scratch without a model.""" + # Create a PropertyFieldsCollection + pfc = PropertyFieldsCollection(server=server_type) + + # Set labels + pfc.labels = ['time', 'body'] + assert pfc.labels == ['time', 'body'] + + # Create property fields and add them + for i in range(3): + label_space = {"time": i+1, "body": 0} + pfield = dpf.PropertyField(server=server_type) + pfield.data = list(range(i*10, (i+1)*10)) + pfc.add_entry(label_space, pfield) + + # Verify collection size + assert len(pfc) == 3 + + # Test get_entries with full label space + entries = pfc.get_entries({"time": 1, "body": 0}) + assert len(entries) >= 1 + assert isinstance(entries[0], dpf.PropertyField) + + # Test get_entries with partial label space + all_time_fields = pfc.get_entries({"body": 0}) + assert len(all_time_fields) == 3 + + # Test get_entry by index + first_field = pfc.get_entry(0) + assert isinstance(first_field, dpf.PropertyField) + + # Test get_entry by label space + time2_field = pfc.get_entry({"time": 2, "body": 0}) + assert isinstance(time2_field, dpf.PropertyField) + + # Test __getitem__ + field_idx = pfc[1] + assert isinstance(field_idx, dpf.PropertyField) + + field_label = pfc[{"time": 3, "body": 0}] + assert isinstance(field_label, dpf.PropertyField) + + # Test get_label_space + ls0 = pfc.get_label_space(0) + assert ls0["time"] == 1 + assert ls0["body"] == 0 + + ls2 = pfc.get_label_space(2) + assert ls2["time"] == 3 + assert ls2["body"] == 0 + + # Test get_label_scoping + time_scoping = pfc.get_label_scoping("time") + assert isinstance(time_scoping, dpf.Scoping) + assert 1 in time_scoping.ids + assert 2 in time_scoping.ids + assert 3 in time_scoping.ids + + # Test get_available_ids_for_label + time_ids = pfc.get_available_ids_for_label("time") + assert 1 in time_ids + assert 2 in time_ids + assert 3 in time_ids + + body_ids = pfc.get_available_ids_for_label("body") + assert 0 in body_ids + + # Test has_label + assert pfc.has_label("time") + assert pfc.has_label("body") + assert not pfc.has_label("complex") + + # Test add_label + pfc.add_label("complex", default_value=0) + assert pfc.has_label("complex") + assert "complex" in pfc.labels From 2c738ed4cff33bce51b48aacf3568dd2b8f62c85 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Mon, 8 Dec 2025 13:01:08 +0100 Subject: [PATCH 05/27] feat: remove commented code --- .../dpf/core/property_fields_container.py | 209 ------------------ 1 file changed, 209 deletions(-) diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_container.py index a2908b3e2d6..9bf5f473415 100644 --- a/src/ansys/dpf/core/property_fields_container.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -68,212 +68,3 @@ class PropertyFieldsCollection(Collection[PropertyField]): def __init__(self, property_fields_collection=None, server=None, entries_type: type = PropertyField): """Initialize a property fields container.""" super().__init__(collection=property_fields_collection, server=server, entries_type=entries_type) - - -# class _LabelSpaceKV: -# """Class for internal use to associate a label space with a field.""" - -# def __init__(self, _dict: Dict[str, int], _field: dpf.Field): -# """Construct an association between a dictionary and a field.""" -# self._dict = _dict -# self._field = _field - -# @property -# def dict(self) -> dict: -# """Returns the associated dictionary.""" -# return self._dict - -# @property -# def field(self) -> dpf.Field: -# """Returns the associated field.""" -# return self._field - -# @field.setter -# def field(self, value: dpf.Field): -# self._field = value - -# def __str__(self): -# """Return a string representation of the association.""" -# field_str = str(self._field).replace("\n", "\n\t\t\t") -# return f"Label Space: {self._dict} with field\n\t\t\t{field_str}" - - - -# class _MockPropertyFieldsContainer(Sequence): -# """Minimal implementation of a FieldsContainer specialized for _MockPropertyFieldsContainer.""" - -# def __init__( -# self, -# fields_container: _MockPropertyFieldsContainer = None, -# server: BaseServer = None, -# ): -# """Construct a _MockPropertyFieldsContainer.""" -# # default constructor -# self._labels = [] # used by Dataframe -# self.scopings = [] -# self._server = None # used by Dataframe - -# self.label_spaces = [] -# self.ids = [] - -# # _MockPropertyFieldsContainer copy -# if fields_container is not None: -# self._labels = copy.deepcopy(fields_container.labels) -# # self.scopings = copy.deepcopy(fields_container.scopings) -# self._server = fields_container._server - -# # self.ids = copy.deepcopy(fields_container.ids) - -# for ls in fields_container.label_spaces: -# self.add_entry(copy.deepcopy(ls.dict), ls.field.as_local_field()) - -# # server copy -# if server is not None: -# self._server = server - -# # Collection -# def __str__(self) -> str: # Exposed in CollectionBase -# """Return a string representation of a _MockPropertyFieldsContainer.""" -# txt = f"DPF PropertyFieldsContainer with {len(self)} fields\n" -# for idx, ls in enumerate(self.label_spaces): -# txt += f"\t {idx}: {ls}\n" - -# return txt - -# @property -# def labels(self) -> List[str]: # Possible through __get_labels in CollectionBase -# """Returns all labels of the _MockPropertyFieldsContainer.""" -# return self._labels - -# @labels.setter # Possible through set_labels in CollectionBase -# def labels(self, labels: List[str]): -# """Set all the label of the _MockPropertyFieldsContainer.""" -# if len(self._labels) != 0: -# raise ValueError("labels already set") -# for l in labels: -# self.add_label(l) - -# def add_label(self, label: str): # Exposed in CollectionBase -# """Add a label.""" -# if label not in self._labels: -# self._labels.append(label) -# self.scopings.append([]) - -# def has_label(self, label) -> bool: # Exposed in CollectionBase -# """Check if a _MockPropertyFieldsContainer contains a given label.""" -# return label in self.labels - -# # used by Dataframe -# def get_label_space(self, idx) -> Dict: # Exposed in CollectionBase -# """Get a Label Space at a given index.""" -# return self.label_spaces[idx].dict - -# # used by Dataframe -# def get_label_scoping(self, label="time") -> dpf.Scoping: # Exposed in CollectionBase -# """Return a scoping on the fields concerned by the given label.""" -# if label in self.labels: -# scoping_ids = self.scopings[self.labels.index(label)] -# return dpf.Scoping(ids=scoping_ids, location="") -# raise KeyError(f"label {label} not found") - -# def add_entry(self, label_space: Dict[str, int], value: dpf.Field): # Exposed in CollectionBase -# """Add a PropertyField associated with a dictionary.""" -# new_id = self._new_id() - -# if hasattr(value, "_server"): -# self._server = value._server - -# # add Label Space -# self.label_spaces.append(_LabelSpaceKV(label_space, value)) - -# # Update IDs -# self.ids.append(new_id) - -# # Update Scopings -# for label in label_space.keys(): -# label_idx = self.labels.index(label) -# self.scopings[label_idx].append(new_id) - -# def add_field(self, label_space: Dict[str, int], field: dpf.Field): # Exposed in CollectionBase (indirectly through _add_entry) -# """Add or update a field at a requested label space.""" -# self.add_entry(label_space, field) - -# def get_entries(self, label_space_or_index: Union[Dict[str, int], int]): # Exposed in CollectionBase -# """Return a list of fields from a complete or partial specification of a dictionary.""" -# if isinstance(label_space_or_index, int): -# idx: int = label_space_or_index -# return [self.label_spaces[idx].field] -# else: -# _dict: Dict[str, int] = label_space_or_index -# are_keys_in_labels = [key in self.labels for key in _dict.keys()] -# if all(are_keys_in_labels): -# remaining = set(range(len(self.label_spaces))) -# for key in _dict.keys(): -# val = _dict[key] -# to_remove = set() -# for idx in remaining: -# ls = self.label_spaces[idx] -# if key in ls.dict.keys(): -# if ls.dict[key] != val: -# to_remove.add(idx) -# else: -# to_remove.add(idx) -# remaining = remaining.difference(to_remove) - -# idx_to_field = lambda idx: self.label_spaces[idx].field -# return list(map(idx_to_field, remaining)) -# else: -# bad_idx = are_keys_in_labels.index(False) -# bad_key = list(_dict.keys())[bad_idx] -# raise KeyError(f"Key {bad_key} is not in labels: {self.labels}") - -# def get_entry(self, label_space_or_index: Union[Dict[str, int], int]): # Exposed in CollectionBase -# """Return the field or (first field found) corresponding to the given dictionary.""" -# ret = self.get_entries(label_space_or_index) - -# if len(ret) != 0: -# return ret[0] - -# raise ValueError("Could not find corresponding entry") - -# def _new_id(self) -> int: # Will no longer be needed -# """Helper-method generating a new id when calling add_entry(...).""" -# if len(self.ids) == 0: -# self.last_id = 1 -# return self.last_id -# else: -# self.last_id += 1 -# return self.last_id - -# # used by Dataframe -# def get_fields(self, label_space: Dict[str, int]) -> List[dpf.Field]: # Exposed in CollectionBase (indirectly through _get_entries) -# """Return the list of fields associated with given label space.""" -# return self.get_entries(label_space) - -# def get_field(self, label_space_or_index: Union[Dict[str, int], int]) -> dpf.Field: # Exposed in CollectionBase (indirectly through _get_entry) -# """Retrieve the field at a requested index or label space.""" -# return self.get_entry(label_space_or_index) - -# # used by Dataframe -# def __getitem__(self, key: Union[Dict[str, int], int]) -> dpf.Field: # Exposed in CollectionBase -# """Retrieve the field at a requested index.""" -# return self.get_field(key) - -# def __len__(self) -> int: # Exposed in CollectionBase -# """Retrieve the number of label spaces.""" -# return len(self.label_spaces) - -# def _set_field(self, ls_idx, field): -# self.label_spaces[ls_idx].field = field - -# def rescope(self, scoping: dpf.Scoping): # Used by post.Dataframe -# """Helper-function to reproduce functionality of rescope_fc Operator.""" -# copy_fc = _MockPropertyFieldsContainer(self, server=None) -# for idx, label_space in enumerate(copy_fc.label_spaces): -# pfield = PropertyField(location=label_space.field.location) -# pfield.data = np.ravel( -# [label_space._field.get_entity_data_by_id(id) for id in scoping.ids] -# ) -# pfield.scoping.ids = scoping.ids -# copy_fc._set_field(idx, pfield) -# return copy_fc From 24c0f021ff45d7828bb54f29c3f28fcecba0f837 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Mon, 8 Dec 2025 13:07:14 +0100 Subject: [PATCH 06/27] fix: codestyle --- .../dpf/core/property_fields_container.py | 8 ++- tests/test_property_fields_container.py | 72 +++++++++---------- 2 files changed, 42 insertions(+), 38 deletions(-) diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_container.py index 9bf5f473415..2394564bd87 100644 --- a/src/ansys/dpf/core/property_fields_container.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -65,6 +65,10 @@ class PropertyFieldsCollection(Collection[PropertyField]): """ - def __init__(self, property_fields_collection=None, server=None, entries_type: type = PropertyField): + def __init__( + self, property_fields_collection=None, server=None, entries_type: type = PropertyField + ): """Initialize a property fields container.""" - super().__init__(collection=property_fields_collection, server=server, entries_type=entries_type) + super().__init__( + collection=property_fields_collection, server=server, entries_type=entries_type + ) diff --git a/tests/test_property_fields_container.py b/tests/test_property_fields_container.py index ddbcc209af6..f41b0a7a88c 100644 --- a/tests/test_property_fields_container.py +++ b/tests/test_property_fields_container.py @@ -29,70 +29,70 @@ def test_property_fields_collection(allkindofcomplexity, server_type): """Test PropertyFieldsCollection class.""" model = dpf.Model(allkindofcomplexity, server=server_type) - + # Create a PropertyFieldsCollection pfc = PropertyFieldsCollection(server=server_type) - + # Test adding labels pfc.add_label(label="test") assert pfc.has_label(label="test") assert pfc.labels == ["test"] - + # Test adding another label pfc.add_label(label="body") assert pfc.has_label(label="body") assert pfc.labels == ["test", "body"] - + # Get a property field from the model property_field = model.metadata.meshed_region.elements.connectivities_field - + # Test add_entry method pfc.add_entry(label_space={"test": 42, "body": 0}, entry=property_field) assert len(pfc) == 1 - + # Test get_label_space label_space = pfc.get_label_space(0) assert label_space == {"test": 42, "body": 0} - + # Test get_label_scoping with pytest.raises(KeyError, match="label test2 not found"): pfc.get_label_scoping("test2") - + scoping = pfc.get_label_scoping("test") assert isinstance(scoping, dpf.Scoping) assert 42 in scoping.ids - + # Test get_entries with label space entries = pfc.get_entries({"test": 42, "body": 0}) assert len(entries) >= 1 retrieved_field = entries[0] assert isinstance(retrieved_field, dpf.PropertyField) - + # Test get_entry with label space entry = pfc.get_entry({"test": 42, "body": 0}) assert isinstance(entry, dpf.PropertyField) - + # Test get_entry with index entry_by_index = pfc.get_entry(0) assert isinstance(entry_by_index, dpf.PropertyField) - + # Test __getitem__ with index field_by_index = pfc[0] assert isinstance(field_by_index, dpf.PropertyField) - + # Test __getitem__ with label space field_by_label = pfc[{"test": 42, "body": 0}] assert isinstance(field_by_label, dpf.PropertyField) - + # Test adding more entries with different label spaces property_field2 = model.metadata.meshed_region.elements.element_types_field pfc.add_entry(label_space={"test": 43, "body": 0}, entry=property_field2) assert len(pfc) == 2 - + # Test retrieving multiple entries with partial label space entries_body0 = pfc.get_entries({"body": 0}) assert len(entries_body0) == 2 - + # Test get_available_ids_for_label test_ids = pfc.get_available_ids_for_label("test") assert 42 in test_ids @@ -103,75 +103,75 @@ def test_property_fields_collection_from_scratch(server_type): """Test creating PropertyFieldsCollection from scratch without a model.""" # Create a PropertyFieldsCollection pfc = PropertyFieldsCollection(server=server_type) - + # Set labels - pfc.labels = ['time', 'body'] - assert pfc.labels == ['time', 'body'] - + pfc.labels = ["time", "body"] + assert pfc.labels == ["time", "body"] + # Create property fields and add them for i in range(3): - label_space = {"time": i+1, "body": 0} + label_space = {"time": i + 1, "body": 0} pfield = dpf.PropertyField(server=server_type) - pfield.data = list(range(i*10, (i+1)*10)) + pfield.data = list(range(i * 10, (i + 1) * 10)) pfc.add_entry(label_space, pfield) - + # Verify collection size assert len(pfc) == 3 - + # Test get_entries with full label space entries = pfc.get_entries({"time": 1, "body": 0}) assert len(entries) >= 1 assert isinstance(entries[0], dpf.PropertyField) - + # Test get_entries with partial label space all_time_fields = pfc.get_entries({"body": 0}) assert len(all_time_fields) == 3 - + # Test get_entry by index first_field = pfc.get_entry(0) assert isinstance(first_field, dpf.PropertyField) - + # Test get_entry by label space time2_field = pfc.get_entry({"time": 2, "body": 0}) assert isinstance(time2_field, dpf.PropertyField) - + # Test __getitem__ field_idx = pfc[1] assert isinstance(field_idx, dpf.PropertyField) - + field_label = pfc[{"time": 3, "body": 0}] assert isinstance(field_label, dpf.PropertyField) - + # Test get_label_space ls0 = pfc.get_label_space(0) assert ls0["time"] == 1 assert ls0["body"] == 0 - + ls2 = pfc.get_label_space(2) assert ls2["time"] == 3 assert ls2["body"] == 0 - + # Test get_label_scoping time_scoping = pfc.get_label_scoping("time") assert isinstance(time_scoping, dpf.Scoping) assert 1 in time_scoping.ids assert 2 in time_scoping.ids assert 3 in time_scoping.ids - + # Test get_available_ids_for_label time_ids = pfc.get_available_ids_for_label("time") assert 1 in time_ids assert 2 in time_ids assert 3 in time_ids - + body_ids = pfc.get_available_ids_for_label("body") assert 0 in body_ids - + # Test has_label assert pfc.has_label("time") assert pfc.has_label("body") assert not pfc.has_label("complex") - + # Test add_label pfc.add_label("complex", default_value=0) assert pfc.has_label("complex") From 868f122e478a60899a881f564e9896c650e89bad Mon Sep 17 00:00:00 2001 From: moe-ad Date: Mon, 8 Dec 2025 13:15:11 +0100 Subject: [PATCH 07/27] fix: doctest --- src/ansys/dpf/core/property_fields_container.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_container.py index 2394564bd87..8f35cb7a030 100644 --- a/src/ansys/dpf/core/property_fields_container.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -61,7 +61,7 @@ class PropertyFieldsCollection(Collection[PropertyField]): ... label_space = {"time": i+1, "body": 0} ... pfield = dpf.PropertyField() ... pfield.data = list(range(i*10, (i+1)*10)) - ... pfc.add_field(label_space, pfield) + ... pfc.add_entry(label_space, pfield) """ From 0a5c504d45b95ab12aa93232228f7681247ac3e5 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Mon, 8 Dec 2025 14:27:13 +0100 Subject: [PATCH 08/27] fix: test --- tests/test_property_fields_container.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_property_fields_container.py b/tests/test_property_fields_container.py index f41b0a7a88c..21054b5c732 100644 --- a/tests/test_property_fields_container.py +++ b/tests/test_property_fields_container.py @@ -41,7 +41,7 @@ def test_property_fields_collection(allkindofcomplexity, server_type): # Test adding another label pfc.add_label(label="body") assert pfc.has_label(label="body") - assert pfc.labels == ["test", "body"] + assert pfc.labels == ["body", "test"] # Get a property field from the model property_field = model.metadata.meshed_region.elements.connectivities_field @@ -106,7 +106,7 @@ def test_property_fields_collection_from_scratch(server_type): # Set labels pfc.labels = ["time", "body"] - assert pfc.labels == ["time", "body"] + assert pfc.labels == ["body", "time"] # Create property fields and add them for i in range(3): From 418e6087f3110f893e03d9d53c43cd7af993bc9c Mon Sep 17 00:00:00 2001 From: Muhammed Adedigba Date: Tue, 9 Dec 2025 12:02:52 +0100 Subject: [PATCH 09/27] fix: test cases --- tests/test_property_fields_container.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/tests/test_property_fields_container.py b/tests/test_property_fields_container.py index 21054b5c732..d653c5cdaf6 100644 --- a/tests/test_property_fields_container.py +++ b/tests/test_property_fields_container.py @@ -54,10 +54,6 @@ def test_property_fields_collection(allkindofcomplexity, server_type): label_space = pfc.get_label_space(0) assert label_space == {"test": 42, "body": 0} - # Test get_label_scoping - with pytest.raises(KeyError, match="label test2 not found"): - pfc.get_label_scoping("test2") - scoping = pfc.get_label_scoping("test") assert isinstance(scoping, dpf.Scoping) assert 42 in scoping.ids @@ -81,7 +77,7 @@ def test_property_fields_collection(allkindofcomplexity, server_type): assert isinstance(field_by_index, dpf.PropertyField) # Test __getitem__ with label space - field_by_label = pfc[{"test": 42, "body": 0}] + field_by_label = pfc.get_entry({"test": 42, "body": 0}) assert isinstance(field_by_label, dpf.PropertyField) # Test adding more entries with different label spaces @@ -139,7 +135,7 @@ def test_property_fields_collection_from_scratch(server_type): field_idx = pfc[1] assert isinstance(field_idx, dpf.PropertyField) - field_label = pfc[{"time": 3, "body": 0}] + field_label = pfc.get_entry({"time": 3, "body": 0}) assert isinstance(field_label, dpf.PropertyField) # Test get_label_space From ad56e7d7af1bd4c7fdc58bb4fbb5fbb8deac90c7 Mon Sep 17 00:00:00 2001 From: Muhammed Adedigba Date: Tue, 9 Dec 2025 12:08:11 +0100 Subject: [PATCH 10/27] fix: rename file --- src/ansys/dpf/core/__init__.py | 2 +- tests/test_property_fields_container.py | 174 ------------------------ 2 files changed, 1 insertion(+), 175 deletions(-) delete mode 100644 tests/test_property_fields_container.py diff --git a/src/ansys/dpf/core/__init__.py b/src/ansys/dpf/core/__init__.py index 45edada1984..2aa8379d0dd 100644 --- a/src/ansys/dpf/core/__init__.py +++ b/src/ansys/dpf/core/__init__.py @@ -39,7 +39,7 @@ from ansys.dpf.core.custom_type_field import CustomTypeField # noqa: F401 from ansys.dpf.core.dimensionality import Dimensionality from ansys.dpf.core.property_field import PropertyField -from ansys.dpf.core.property_fields_container import PropertyFieldsCollection +from ansys.dpf.core.property_fields_collection import PropertyFieldsCollection from ansys.dpf.core.string_field import StringField from ansys.dpf.core.fields_container import FieldsContainer from ansys.dpf.core.meshes_container import MeshesContainer diff --git a/tests/test_property_fields_container.py b/tests/test_property_fields_container.py deleted file mode 100644 index d653c5cdaf6..00000000000 --- a/tests/test_property_fields_container.py +++ /dev/null @@ -1,174 +0,0 @@ -# Copyright (C) 2020 - 2025 ANSYS, Inc. and/or its affiliates. -# SPDX-License-Identifier: MIT -# -# -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. - -import pytest - -from ansys.dpf import core as dpf -from ansys.dpf.core.property_fields_container import PropertyFieldsCollection - - -def test_property_fields_collection(allkindofcomplexity, server_type): - """Test PropertyFieldsCollection class.""" - model = dpf.Model(allkindofcomplexity, server=server_type) - - # Create a PropertyFieldsCollection - pfc = PropertyFieldsCollection(server=server_type) - - # Test adding labels - pfc.add_label(label="test") - assert pfc.has_label(label="test") - assert pfc.labels == ["test"] - - # Test adding another label - pfc.add_label(label="body") - assert pfc.has_label(label="body") - assert pfc.labels == ["body", "test"] - - # Get a property field from the model - property_field = model.metadata.meshed_region.elements.connectivities_field - - # Test add_entry method - pfc.add_entry(label_space={"test": 42, "body": 0}, entry=property_field) - assert len(pfc) == 1 - - # Test get_label_space - label_space = pfc.get_label_space(0) - assert label_space == {"test": 42, "body": 0} - - scoping = pfc.get_label_scoping("test") - assert isinstance(scoping, dpf.Scoping) - assert 42 in scoping.ids - - # Test get_entries with label space - entries = pfc.get_entries({"test": 42, "body": 0}) - assert len(entries) >= 1 - retrieved_field = entries[0] - assert isinstance(retrieved_field, dpf.PropertyField) - - # Test get_entry with label space - entry = pfc.get_entry({"test": 42, "body": 0}) - assert isinstance(entry, dpf.PropertyField) - - # Test get_entry with index - entry_by_index = pfc.get_entry(0) - assert isinstance(entry_by_index, dpf.PropertyField) - - # Test __getitem__ with index - field_by_index = pfc[0] - assert isinstance(field_by_index, dpf.PropertyField) - - # Test __getitem__ with label space - field_by_label = pfc.get_entry({"test": 42, "body": 0}) - assert isinstance(field_by_label, dpf.PropertyField) - - # Test adding more entries with different label spaces - property_field2 = model.metadata.meshed_region.elements.element_types_field - pfc.add_entry(label_space={"test": 43, "body": 0}, entry=property_field2) - assert len(pfc) == 2 - - # Test retrieving multiple entries with partial label space - entries_body0 = pfc.get_entries({"body": 0}) - assert len(entries_body0) == 2 - - # Test get_available_ids_for_label - test_ids = pfc.get_available_ids_for_label("test") - assert 42 in test_ids - assert 43 in test_ids - - -def test_property_fields_collection_from_scratch(server_type): - """Test creating PropertyFieldsCollection from scratch without a model.""" - # Create a PropertyFieldsCollection - pfc = PropertyFieldsCollection(server=server_type) - - # Set labels - pfc.labels = ["time", "body"] - assert pfc.labels == ["body", "time"] - - # Create property fields and add them - for i in range(3): - label_space = {"time": i + 1, "body": 0} - pfield = dpf.PropertyField(server=server_type) - pfield.data = list(range(i * 10, (i + 1) * 10)) - pfc.add_entry(label_space, pfield) - - # Verify collection size - assert len(pfc) == 3 - - # Test get_entries with full label space - entries = pfc.get_entries({"time": 1, "body": 0}) - assert len(entries) >= 1 - assert isinstance(entries[0], dpf.PropertyField) - - # Test get_entries with partial label space - all_time_fields = pfc.get_entries({"body": 0}) - assert len(all_time_fields) == 3 - - # Test get_entry by index - first_field = pfc.get_entry(0) - assert isinstance(first_field, dpf.PropertyField) - - # Test get_entry by label space - time2_field = pfc.get_entry({"time": 2, "body": 0}) - assert isinstance(time2_field, dpf.PropertyField) - - # Test __getitem__ - field_idx = pfc[1] - assert isinstance(field_idx, dpf.PropertyField) - - field_label = pfc.get_entry({"time": 3, "body": 0}) - assert isinstance(field_label, dpf.PropertyField) - - # Test get_label_space - ls0 = pfc.get_label_space(0) - assert ls0["time"] == 1 - assert ls0["body"] == 0 - - ls2 = pfc.get_label_space(2) - assert ls2["time"] == 3 - assert ls2["body"] == 0 - - # Test get_label_scoping - time_scoping = pfc.get_label_scoping("time") - assert isinstance(time_scoping, dpf.Scoping) - assert 1 in time_scoping.ids - assert 2 in time_scoping.ids - assert 3 in time_scoping.ids - - # Test get_available_ids_for_label - time_ids = pfc.get_available_ids_for_label("time") - assert 1 in time_ids - assert 2 in time_ids - assert 3 in time_ids - - body_ids = pfc.get_available_ids_for_label("body") - assert 0 in body_ids - - # Test has_label - assert pfc.has_label("time") - assert pfc.has_label("body") - assert not pfc.has_label("complex") - - # Test add_label - pfc.add_label("complex", default_value=0) - assert pfc.has_label("complex") - assert "complex" in pfc.labels From e8f5e927260fcf9d5aa7864e57b5c9027f960f31 Mon Sep 17 00:00:00 2001 From: Muhammed Adedigba Date: Tue, 9 Dec 2025 12:13:37 +0100 Subject: [PATCH 11/27] fix: rename file --- ...property_fields_container.py => property_fields_collection.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/ansys/dpf/core/{property_fields_container.py => property_fields_collection.py} (100%) diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_collection.py similarity index 100% rename from src/ansys/dpf/core/property_fields_container.py rename to src/ansys/dpf/core/property_fields_collection.py From 3d6801db41ffc6095623457e708198563953fe4d Mon Sep 17 00:00:00 2001 From: Muhammed Adedigba Date: Tue, 9 Dec 2025 12:49:35 +0100 Subject: [PATCH 12/27] fix: add renamed test file --- tests/test_property_fields_collection.py | 174 +++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 tests/test_property_fields_collection.py diff --git a/tests/test_property_fields_collection.py b/tests/test_property_fields_collection.py new file mode 100644 index 00000000000..e1c3ca4eab4 --- /dev/null +++ b/tests/test_property_fields_collection.py @@ -0,0 +1,174 @@ +# Copyright (C) 2020 - 2025 ANSYS, Inc. and/or its affiliates. +# SPDX-License-Identifier: MIT +# +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +# SOFTWARE. + +import pytest + +from ansys.dpf import core as dpf +from ansys.dpf.core.property_fields_collection import PropertyFieldsCollection + + +def test_property_fields_collection(allkindofcomplexity, server_type): + """Test PropertyFieldsCollection class.""" + model = dpf.Model(allkindofcomplexity, server=server_type) + + # Create a PropertyFieldsCollection + pfc = PropertyFieldsCollection(server=server_type) + + # Test adding labels + pfc.add_label(label="test") + assert pfc.has_label(label="test") + assert pfc.labels == ["test"] + + # Test adding another label + pfc.add_label(label="body") + assert pfc.has_label(label="body") + assert pfc.labels == ["body", "test"] + + # Get a property field from the model + property_field = model.metadata.meshed_region.elements.connectivities_field + + # Test add_entry method + pfc.add_entry(label_space={"test": 42, "body": 0}, entry=property_field) + assert len(pfc) == 1 + + # Test get_label_space + label_space = pfc.get_label_space(0) + assert label_space == {"test": 42, "body": 0} + + scoping = pfc.get_label_scoping("test") + assert isinstance(scoping, dpf.Scoping) + assert 42 in scoping.ids + + # Test get_entries with label space + entries = pfc.get_entries({"test": 42, "body": 0}) + assert len(entries) >= 1 + retrieved_field = entries[0] + assert isinstance(retrieved_field, dpf.PropertyField) + + # Test get_entry with label space + entry = pfc.get_entry({"test": 42, "body": 0}) + assert isinstance(entry, dpf.PropertyField) + + # Test get_entry with index + entry_by_index = pfc.get_entry(0) + assert isinstance(entry_by_index, dpf.PropertyField) + + # Test __getitem__ with index + field_by_index = pfc[0] + assert isinstance(field_by_index, dpf.PropertyField) + + # Test __getitem__ with label space + field_by_label = pfc.get_entry({"test": 42, "body": 0}) + assert isinstance(field_by_label, dpf.PropertyField) + + # Test adding more entries with different label spaces + property_field2 = model.metadata.meshed_region.elements.element_types_field + pfc.add_entry(label_space={"test": 43, "body": 0}, entry=property_field2) + assert len(pfc) == 2 + + # Test retrieving multiple entries with partial label space + entries_body0 = pfc.get_entries({"body": 0}) + assert len(entries_body0) == 2 + + # Test get_available_ids_for_label + test_ids = pfc.get_available_ids_for_label("test") + assert 42 in test_ids + assert 43 in test_ids + + +def test_property_fields_collection_from_scratch(server_type): + """Test creating PropertyFieldsCollection from scratch without a model.""" + # Create a PropertyFieldsCollection + pfc = PropertyFieldsCollection(server=server_type) + + # Set labels + pfc.labels = ["time", "body"] + assert pfc.labels == ["body", "time"] + + # Create property fields and add them + for i in range(3): + label_space = {"time": i + 1, "body": 0} + pfield = dpf.PropertyField(server=server_type) + pfield.data = list(range(i * 10, (i + 1) * 10)) + pfc.add_entry(label_space, pfield) + + # Verify collection size + assert len(pfc) == 3 + + # Test get_entries with full label space + entries = pfc.get_entries({"time": 1, "body": 0}) + assert len(entries) >= 1 + assert isinstance(entries[0], dpf.PropertyField) + + # Test get_entries with partial label space + all_time_fields = pfc.get_entries({"body": 0}) + assert len(all_time_fields) == 3 + + # Test get_entry by index + first_field = pfc.get_entry(0) + assert isinstance(first_field, dpf.PropertyField) + + # Test get_entry by label space + time2_field = pfc.get_entry({"time": 2, "body": 0}) + assert isinstance(time2_field, dpf.PropertyField) + + # Test __getitem__ + field_idx = pfc[1] + assert isinstance(field_idx, dpf.PropertyField) + + field_label = pfc.get_entry({"time": 3, "body": 0}) + assert isinstance(field_label, dpf.PropertyField) + + # Test get_label_space + ls0 = pfc.get_label_space(0) + assert ls0["time"] == 1 + assert ls0["body"] == 0 + + ls2 = pfc.get_label_space(2) + assert ls2["time"] == 3 + assert ls2["body"] == 0 + + # Test get_label_scoping + time_scoping = pfc.get_label_scoping("time") + assert isinstance(time_scoping, dpf.Scoping) + assert 1 in time_scoping.ids + assert 2 in time_scoping.ids + assert 3 in time_scoping.ids + + # Test get_available_ids_for_label + time_ids = pfc.get_available_ids_for_label("time") + assert 1 in time_ids + assert 2 in time_ids + assert 3 in time_ids + + body_ids = pfc.get_available_ids_for_label("body") + assert 0 in body_ids + + # Test has_label + assert pfc.has_label("time") + assert pfc.has_label("body") + assert not pfc.has_label("complex") + + # Test add_label + pfc.add_label("complex", default_value=0) + assert pfc.has_label("complex") + assert "complex" in pfc.labels From 8db86effc8ecb4c57250a665cabf9159a034182a Mon Sep 17 00:00:00 2001 From: moe-ad Date: Tue, 9 Dec 2025 13:23:07 +0100 Subject: [PATCH 13/27] fix: avoid circular import --- src/ansys/dpf/core/property_fields_collection.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/ansys/dpf/core/property_fields_collection.py b/src/ansys/dpf/core/property_fields_collection.py index 8f35cb7a030..544bc284961 100644 --- a/src/ansys/dpf/core/property_fields_collection.py +++ b/src/ansys/dpf/core/property_fields_collection.py @@ -28,11 +28,11 @@ from __future__ import annotations -from ansys.dpf.core import PropertyField +from ansys.dpf.core import property_field from ansys.dpf.core.collection import Collection -class PropertyFieldsCollection(Collection[PropertyField]): +class PropertyFieldsCollection(Collection["property_field.PropertyField"]): """Represents a property fields collection, which contains property fields. A property fields collection is a set of property fields ordered by labels and IDs. @@ -66,7 +66,7 @@ class PropertyFieldsCollection(Collection[PropertyField]): """ def __init__( - self, property_fields_collection=None, server=None, entries_type: type = PropertyField + self, property_fields_collection=None, server=None, entries_type: type = property_field.PropertyField ): """Initialize a property fields container.""" super().__init__( From 0164ad022c1d154c7de4b662f75a25b013751cbf Mon Sep 17 00:00:00 2001 From: moe-ad Date: Tue, 9 Dec 2025 13:25:20 +0100 Subject: [PATCH 14/27] fix: codestyle --- src/ansys/dpf/core/property_fields_collection.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ansys/dpf/core/property_fields_collection.py b/src/ansys/dpf/core/property_fields_collection.py index 544bc284961..00fd985d39e 100644 --- a/src/ansys/dpf/core/property_fields_collection.py +++ b/src/ansys/dpf/core/property_fields_collection.py @@ -66,7 +66,10 @@ class PropertyFieldsCollection(Collection["property_field.PropertyField"]): """ def __init__( - self, property_fields_collection=None, server=None, entries_type: type = property_field.PropertyField + self, + property_fields_collection=None, + server=None, + entries_type: type = property_field.PropertyField, ): """Initialize a property fields container.""" super().__init__( From e8226d7866e6d92f08ff151bec4a4ac2e327a1a5 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Wed, 10 Dec 2025 10:01:39 +0100 Subject: [PATCH 15/27] feat: update code generation scripts --- src/ansys/dpf/core/mapping_types.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/ansys/dpf/core/mapping_types.py b/src/ansys/dpf/core/mapping_types.py index d11bd69b7e5..e76784ad03a 100644 --- a/src/ansys/dpf/core/mapping_types.py +++ b/src/ansys/dpf/core/mapping_types.py @@ -61,6 +61,7 @@ map_types_to_cpp["float"] = "double" map_types_to_cpp["UnitSystem"] = "class dataProcessing::unit::CUnitSystem" map_types_to_cpp["dict"] = "label_space" +map_types_to_cpp["PropertyFieldsCollection"] = "class dataProcessing::DpfTypeCollection" class _smart_dict_snake(dict): @@ -76,6 +77,7 @@ def __missing__(self, key): map_types_to_python["vector"] = "list[float]" map_types_to_python["vector"] = "list[str]" map_types_to_python["b"] = "bool" +map_types_to_python["property_fields_container"] = "PropertyFieldsCollection" def reflection_type_to_cpp_type(reflection_type: str) -> str: From 24da8ecea7e4aa4d528a9eea3dbf1f0df8d8addc Mon Sep 17 00:00:00 2001 From: moe-ad Date: Wed, 10 Dec 2025 10:50:10 +0100 Subject: [PATCH 16/27] feat: further updates to code generation scripts --- src/ansys/dpf/core/operators/build.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/ansys/dpf/core/operators/build.py b/src/ansys/dpf/core/operators/build.py index 66e6f653cf6..096d2e4029a 100644 --- a/src/ansys/dpf/core/operators/build.py +++ b/src/ansys/dpf/core/operators/build.py @@ -130,6 +130,11 @@ def build_pin_data(pins, output=False): specification = pins[id] type_names = specification.type_names + # Process type_names for property_fields_container --> property_fields_collection + type_names = [ + name.replace("property_fields_container", "property_fields_collection") + for name in type_names + ] derived_class_type_name = specification.name_derived_class @@ -149,6 +154,8 @@ def build_pin_data(pins, output=False): pin_name = specification.name pin_name = pin_name.replace("<", "_") pin_name = pin_name.replace(">", "_") + # Process pin name for property_fields_container --> property_fields_collection + pin_name = pin_name.replace("property_fields_container", "property_fields_collection") main_type = docstring_types[0] if len(docstring_types) >= 1 else "" @@ -221,6 +228,9 @@ def build_operator( multiple_output_types = any(pin["multiple_types"] for pin in output_pins) has_output_aliases = any(len(pin["aliases_list"]) > 0 for pin in output_pins) + # Process specification description for property_fields_container --> property_fields_collection + specification_description = specification_description.replace("property_fields_container", "property_fields_collection") + docstring = build_docstring(specification_description) date_and_time = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") @@ -247,6 +257,9 @@ def build_operator( annotation_import_list.sort(key= lambda x: x["class_name"].split("ansys.dpf.core.")[-1]) non_empty_annotation_import_list = bool(annotation_import_list) + # Process operator name for property_fields_container --> property_fields_collection + operator_name = operator_name.replace("property_fields_container", "property_fields_collection") + data = { "operator_name": operator_name, "class_name": class_name, From b36c921d11799aa330c35e6298222c49e48c1e66 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Wed, 10 Dec 2025 11:13:31 +0100 Subject: [PATCH 17/27] test: skip tests for server versions < 8.1 --- tests/test_property_fields_collection.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/tests/test_property_fields_collection.py b/tests/test_property_fields_collection.py index e1c3ca4eab4..d81a5d07f70 100644 --- a/tests/test_property_fields_collection.py +++ b/tests/test_property_fields_collection.py @@ -25,7 +25,11 @@ from ansys.dpf import core as dpf from ansys.dpf.core.property_fields_collection import PropertyFieldsCollection +import conftest +@pytest.mark.skipif( + not conftest.SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_8_1, reason="Available for servers >=8.1" +) def test_property_fields_collection(allkindofcomplexity, server_type): """Test PropertyFieldsCollection class.""" model = dpf.Model(allkindofcomplexity, server=server_type) @@ -94,7 +98,9 @@ def test_property_fields_collection(allkindofcomplexity, server_type): assert 42 in test_ids assert 43 in test_ids - +@pytest.mark.skipif( + not conftest.SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_8_1, reason="Available for servers >=8.1" +) def test_property_fields_collection_from_scratch(server_type): """Test creating PropertyFieldsCollection from scratch without a model.""" # Create a PropertyFieldsCollection From 2195aa72727d9c93de80087e478e6ddb759fe12c Mon Sep 17 00:00:00 2001 From: moe-ad Date: Wed, 10 Dec 2025 11:17:11 +0100 Subject: [PATCH 18/27] fix: codestyle --- src/ansys/dpf/core/mapping_types.py | 4 +++- tests/test_property_fields_collection.py | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ansys/dpf/core/mapping_types.py b/src/ansys/dpf/core/mapping_types.py index e76784ad03a..91d7070caf9 100644 --- a/src/ansys/dpf/core/mapping_types.py +++ b/src/ansys/dpf/core/mapping_types.py @@ -61,7 +61,9 @@ map_types_to_cpp["float"] = "double" map_types_to_cpp["UnitSystem"] = "class dataProcessing::unit::CUnitSystem" map_types_to_cpp["dict"] = "label_space" -map_types_to_cpp["PropertyFieldsCollection"] = "class dataProcessing::DpfTypeCollection" +map_types_to_cpp["PropertyFieldsCollection"] = ( + "class dataProcessing::DpfTypeCollection" +) class _smart_dict_snake(dict): diff --git a/tests/test_property_fields_collection.py b/tests/test_property_fields_collection.py index d81a5d07f70..90ba0973fed 100644 --- a/tests/test_property_fields_collection.py +++ b/tests/test_property_fields_collection.py @@ -24,9 +24,9 @@ from ansys.dpf import core as dpf from ansys.dpf.core.property_fields_collection import PropertyFieldsCollection - import conftest + @pytest.mark.skipif( not conftest.SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_8_1, reason="Available for servers >=8.1" ) @@ -98,6 +98,7 @@ def test_property_fields_collection(allkindofcomplexity, server_type): assert 42 in test_ids assert 43 in test_ids + @pytest.mark.skipif( not conftest.SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_8_1, reason="Available for servers >=8.1" ) From 6f3e2c0c23984f67b412b2b789dbee5dfca369aa Mon Sep 17 00:00:00 2001 From: moe-ad Date: Wed, 10 Dec 2025 11:27:55 +0100 Subject: [PATCH 19/27] feat: update code generation script --- src/ansys/dpf/core/operators/build.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/dpf/core/operators/build.py b/src/ansys/dpf/core/operators/build.py index 096d2e4029a..77cb1a5f126 100644 --- a/src/ansys/dpf/core/operators/build.py +++ b/src/ansys/dpf/core/operators/build.py @@ -230,6 +230,7 @@ def build_operator( # Process specification description for property_fields_container --> property_fields_collection specification_description = specification_description.replace("property_fields_container", "property_fields_collection") + specification_description = specification_description.replace("PropertyFieldsContainer", "PropertyFieldsCollection") docstring = build_docstring(specification_description) From 82b63f03644c42f39685e7f3b440ff7abef56353 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Wed, 10 Dec 2025 12:22:13 +0100 Subject: [PATCH 20/27] fix: retain original operator name --- src/ansys/dpf/core/operators/build.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ansys/dpf/core/operators/build.py b/src/ansys/dpf/core/operators/build.py index 77cb1a5f126..2be9b3ffd52 100644 --- a/src/ansys/dpf/core/operators/build.py +++ b/src/ansys/dpf/core/operators/build.py @@ -258,9 +258,6 @@ def build_operator( annotation_import_list.sort(key= lambda x: x["class_name"].split("ansys.dpf.core.")[-1]) non_empty_annotation_import_list = bool(annotation_import_list) - # Process operator name for property_fields_container --> property_fields_collection - operator_name = operator_name.replace("property_fields_container", "property_fields_collection") - data = { "operator_name": operator_name, "class_name": class_name, From c06d3639a53135316cfbca56397dfe7deb46d105 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Wed, 10 Dec 2025 15:53:21 +0100 Subject: [PATCH 21/27] fix: revert to property fields container --- src/ansys/dpf/core/__init__.py | 2 +- src/ansys/dpf/core/mapping_types.py | 3 +-- src/ansys/dpf/core/operators/build.py | 10 -------- ...ection.py => property_fields_container.py} | 24 +++++++++---------- ...n.py => test_property_fields_container.py} | 0 5 files changed, 14 insertions(+), 25 deletions(-) rename src/ansys/dpf/core/{property_fields_collection.py => property_fields_container.py} (74%) rename tests/{test_property_fields_collection.py => test_property_fields_container.py} (100%) diff --git a/src/ansys/dpf/core/__init__.py b/src/ansys/dpf/core/__init__.py index 2aa8379d0dd..1711c6be30b 100644 --- a/src/ansys/dpf/core/__init__.py +++ b/src/ansys/dpf/core/__init__.py @@ -39,7 +39,7 @@ from ansys.dpf.core.custom_type_field import CustomTypeField # noqa: F401 from ansys.dpf.core.dimensionality import Dimensionality from ansys.dpf.core.property_field import PropertyField -from ansys.dpf.core.property_fields_collection import PropertyFieldsCollection +from ansys.dpf.core.property_fields_container import PropertyFieldsContainer from ansys.dpf.core.string_field import StringField from ansys.dpf.core.fields_container import FieldsContainer from ansys.dpf.core.meshes_container import MeshesContainer diff --git a/src/ansys/dpf/core/mapping_types.py b/src/ansys/dpf/core/mapping_types.py index 91d7070caf9..a96a6d00dee 100644 --- a/src/ansys/dpf/core/mapping_types.py +++ b/src/ansys/dpf/core/mapping_types.py @@ -61,7 +61,7 @@ map_types_to_cpp["float"] = "double" map_types_to_cpp["UnitSystem"] = "class dataProcessing::unit::CUnitSystem" map_types_to_cpp["dict"] = "label_space" -map_types_to_cpp["PropertyFieldsCollection"] = ( +map_types_to_cpp["PropertyFieldsContainer"] = ( "class dataProcessing::DpfTypeCollection" ) @@ -79,7 +79,6 @@ def __missing__(self, key): map_types_to_python["vector"] = "list[float]" map_types_to_python["vector"] = "list[str]" map_types_to_python["b"] = "bool" -map_types_to_python["property_fields_container"] = "PropertyFieldsCollection" def reflection_type_to_cpp_type(reflection_type: str) -> str: diff --git a/src/ansys/dpf/core/operators/build.py b/src/ansys/dpf/core/operators/build.py index 2be9b3ffd52..c89ab38b371 100644 --- a/src/ansys/dpf/core/operators/build.py +++ b/src/ansys/dpf/core/operators/build.py @@ -130,11 +130,6 @@ def build_pin_data(pins, output=False): specification = pins[id] type_names = specification.type_names - # Process type_names for property_fields_container --> property_fields_collection - type_names = [ - name.replace("property_fields_container", "property_fields_collection") - for name in type_names - ] derived_class_type_name = specification.name_derived_class @@ -154,8 +149,6 @@ def build_pin_data(pins, output=False): pin_name = specification.name pin_name = pin_name.replace("<", "_") pin_name = pin_name.replace(">", "_") - # Process pin name for property_fields_container --> property_fields_collection - pin_name = pin_name.replace("property_fields_container", "property_fields_collection") main_type = docstring_types[0] if len(docstring_types) >= 1 else "" @@ -228,9 +221,6 @@ def build_operator( multiple_output_types = any(pin["multiple_types"] for pin in output_pins) has_output_aliases = any(len(pin["aliases_list"]) > 0 for pin in output_pins) - # Process specification description for property_fields_container --> property_fields_collection - specification_description = specification_description.replace("property_fields_container", "property_fields_collection") - specification_description = specification_description.replace("PropertyFieldsContainer", "PropertyFieldsCollection") docstring = build_docstring(specification_description) diff --git a/src/ansys/dpf/core/property_fields_collection.py b/src/ansys/dpf/core/property_fields_container.py similarity index 74% rename from src/ansys/dpf/core/property_fields_collection.py rename to src/ansys/dpf/core/property_fields_container.py index 00fd985d39e..4ca97bc14bb 100644 --- a/src/ansys/dpf/core/property_fields_collection.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -21,9 +21,9 @@ # SOFTWARE. """ -PropertyFieldsCollection. +PropertyFieldsContainer. -Contains classes associated with the PropertyFieldsCollection. +Contains classes associated with the PropertyFieldsContainer. """ from __future__ import annotations @@ -32,18 +32,18 @@ from ansys.dpf.core.collection import Collection -class PropertyFieldsCollection(Collection["property_field.PropertyField"]): - """Represents a property fields collection, which contains property fields. +class PropertyFieldsContainer(Collection["property_field.PropertyField"]): + """Represents a property fields container, which contains property fields. - A property fields collection is a set of property fields ordered by labels and IDs. + A property fields container is a set of property fields ordered by labels and IDs. Each property field in the collection has an ID for each label, allowing flexible organization and retrieval of property fields based on various criteria. Parameters ---------- - property_fields_collection : ansys.grpc.dpf.collection_message_pb2.Collection, ctypes.c_void_p, - PropertyFieldsCollection, optional - Property fields collection created from either a collection message or by copying + property_fields_container : ansys.grpc.dpf.collection_message_pb2.Collection, ctypes.c_void_p, + PropertyFieldsContainer, optional + Property fields container created from either a collection message or by copying an existing one. The default is ``None``. server : ansys.dpf.core.server, optional Server with the channel connected to the remote or local instance. @@ -52,10 +52,10 @@ class PropertyFieldsCollection(Collection["property_field.PropertyField"]): Examples -------- - Create a property fields collection from scratch. + Create a property fields container from scratch. >>> from ansys.dpf import core as dpf - >>> pfc = dpf.PropertyFieldsCollection() + >>> pfc = dpf.PropertyFieldsContainer() >>> pfc.labels = ['time', 'body'] >>> for i in range(0, 5): ... label_space = {"time": i+1, "body": 0} @@ -67,11 +67,11 @@ class PropertyFieldsCollection(Collection["property_field.PropertyField"]): def __init__( self, - property_fields_collection=None, + property_fields_container=None, server=None, entries_type: type = property_field.PropertyField, ): """Initialize a property fields container.""" super().__init__( - collection=property_fields_collection, server=server, entries_type=entries_type + collection=property_fields_container, server=server, entries_type=entries_type ) diff --git a/tests/test_property_fields_collection.py b/tests/test_property_fields_container.py similarity index 100% rename from tests/test_property_fields_collection.py rename to tests/test_property_fields_container.py From e1da5d1dcf311c5b13cf8986b587bb2fa86d3d42 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Wed, 10 Dec 2025 16:20:41 +0100 Subject: [PATCH 22/27] fix: final fix --- src/ansys/dpf/core/mapping_types.py | 1 - src/ansys/dpf/core/operators/build.py | 2 -- tests/test_property_fields_container.py | 18 +++++++++--------- 3 files changed, 9 insertions(+), 12 deletions(-) diff --git a/src/ansys/dpf/core/mapping_types.py b/src/ansys/dpf/core/mapping_types.py index a96a6d00dee..ef43410c13a 100644 --- a/src/ansys/dpf/core/mapping_types.py +++ b/src/ansys/dpf/core/mapping_types.py @@ -80,7 +80,6 @@ def __missing__(self, key): map_types_to_python["vector"] = "list[str]" map_types_to_python["b"] = "bool" - def reflection_type_to_cpp_type(reflection_type: str) -> str: """Convert a reflection type to its corresponding C++ type. diff --git a/src/ansys/dpf/core/operators/build.py b/src/ansys/dpf/core/operators/build.py index c89ab38b371..35ca83cea22 100644 --- a/src/ansys/dpf/core/operators/build.py +++ b/src/ansys/dpf/core/operators/build.py @@ -43,7 +43,6 @@ "MeshSelectionManager", "Class Dataprocessing::Dpftypecollection", "Struct Iansdispatch", - "PropertyFieldsContainer", "Class Dataprocessing::Crstfilewrapper", "Char", ) @@ -221,7 +220,6 @@ def build_operator( multiple_output_types = any(pin["multiple_types"] for pin in output_pins) has_output_aliases = any(len(pin["aliases_list"]) > 0 for pin in output_pins) - docstring = build_docstring(specification_description) date_and_time = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") diff --git a/tests/test_property_fields_container.py b/tests/test_property_fields_container.py index 90ba0973fed..084439e1011 100644 --- a/tests/test_property_fields_container.py +++ b/tests/test_property_fields_container.py @@ -23,19 +23,19 @@ import pytest from ansys.dpf import core as dpf -from ansys.dpf.core.property_fields_collection import PropertyFieldsCollection +from ansys.dpf.core.property_fields_container import PropertyFieldsContainer import conftest @pytest.mark.skipif( not conftest.SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_8_1, reason="Available for servers >=8.1" ) -def test_property_fields_collection(allkindofcomplexity, server_type): - """Test PropertyFieldsCollection class.""" +def test_property_fields_container(allkindofcomplexity, server_type): + """Test PropertyFieldsContainer class.""" model = dpf.Model(allkindofcomplexity, server=server_type) - # Create a PropertyFieldsCollection - pfc = PropertyFieldsCollection(server=server_type) + # Create a PropertyFieldsContainer + pfc = PropertyFieldsContainer(server=server_type) # Test adding labels pfc.add_label(label="test") @@ -102,10 +102,10 @@ def test_property_fields_collection(allkindofcomplexity, server_type): @pytest.mark.skipif( not conftest.SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_8_1, reason="Available for servers >=8.1" ) -def test_property_fields_collection_from_scratch(server_type): - """Test creating PropertyFieldsCollection from scratch without a model.""" - # Create a PropertyFieldsCollection - pfc = PropertyFieldsCollection(server=server_type) +def test_property_fields_container_from_scratch(server_type): + """Test creating PropertyFieldsContainer from scratch without a model.""" + # Create a PropertyFieldsContainer + pfc = PropertyFieldsContainer(server=server_type) # Set labels pfc.labels = ["time", "body"] From 56bb467efc0993c12630c64a633b09892af1f107 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Wed, 10 Dec 2025 17:16:04 +0100 Subject: [PATCH 23/27] fix: codestyle --- src/ansys/dpf/core/mapping_types.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ansys/dpf/core/mapping_types.py b/src/ansys/dpf/core/mapping_types.py index ef43410c13a..a96a6d00dee 100644 --- a/src/ansys/dpf/core/mapping_types.py +++ b/src/ansys/dpf/core/mapping_types.py @@ -80,6 +80,7 @@ def __missing__(self, key): map_types_to_python["vector"] = "list[str]" map_types_to_python["b"] = "bool" + def reflection_type_to_cpp_type(reflection_type: str) -> str: """Convert a reflection type to its corresponding C++ type. From 063cbc6932ca613d2dcd8977b358c03194e45df4 Mon Sep 17 00:00:00 2001 From: PyAnsys CI Bot <92810346+pyansys-ci-bot@users.noreply.github.com> Date: Thu, 11 Dec 2025 03:08:47 +0100 Subject: [PATCH 24/27] Update generated code for DPF 261 on feat/expose-property-fields-container (#2829) Co-authored-by: moe-ad <68085496+moe-ad@users.noreply.github.com> --- .../averaging/elemental_nodal_to_nodal_fc.py | 8 +++---- .../core/operators/logic/enrich_materials.py | 5 ++-- .../dpf/core/operators/logic/identical_pfc.py | 12 ++++++---- .../mapdl_split_to_acmo_facet_indices.py | 9 ++++---- .../scoping/rescope_property_field.py | 5 ++-- .../core/operators/utility/extract_scoping.py | 3 +++ .../utility/merge_property_fields.py | 9 ++++---- .../merge_weighted_fields_containers.py | 23 +++++++++---------- .../utility/propertyfield_get_attribute.py | 5 ++-- 9 files changed, 45 insertions(+), 34 deletions(-) diff --git a/src/ansys/dpf/core/operators/averaging/elemental_nodal_to_nodal_fc.py b/src/ansys/dpf/core/operators/averaging/elemental_nodal_to_nodal_fc.py index aee8c51866d..af8c4457d08 100644 --- a/src/ansys/dpf/core/operators/averaging/elemental_nodal_to_nodal_fc.py +++ b/src/ansys/dpf/core/operators/averaging/elemental_nodal_to_nodal_fc.py @@ -19,6 +19,7 @@ from ansys.dpf.core.fields_container import FieldsContainer from ansys.dpf.core.meshed_region import MeshedRegion from ansys.dpf.core.meshes_container import MeshesContainer + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer from ansys.dpf.core.scoping import Scoping from ansys.dpf.core.scopings_container import ScopingsContainer @@ -52,8 +53,7 @@ class elemental_nodal_to_nodal_fc(Operator): Outputs ------- fields_container: FieldsContainer - weights: Class Dataprocessing::Dpftypecollection<Class - Dataprocessing::Cpropertyfield> + weights: PropertyFieldsContainer Gives for each node, the number of times it was found in the Elemental Nodal field. Can be used to average later. Examples @@ -507,7 +507,7 @@ def __init__(self, op: Operator): elemental_nodal_to_nodal_fc._spec().output_pin(0), 0, op ) self._outputs.append(self._fields_container) - self._weights: Output = Output( + self._weights: Output[PropertyFieldsContainer] = Output( elemental_nodal_to_nodal_fc._spec().output_pin(1), 1, op ) self._outputs.append(self._weights) @@ -531,7 +531,7 @@ def fields_container(self) -> Output[FieldsContainer]: return self._fields_container @property - def weights(self) -> Output: + def weights(self) -> Output[PropertyFieldsContainer]: r"""Allows to get weights output of the operator Gives for each node, the number of times it was found in the Elemental Nodal field. Can be used to average later. diff --git a/src/ansys/dpf/core/operators/logic/enrich_materials.py b/src/ansys/dpf/core/operators/logic/enrich_materials.py index 47237413da3..e41e9ecc446 100644 --- a/src/ansys/dpf/core/operators/logic/enrich_materials.py +++ b/src/ansys/dpf/core/operators/logic/enrich_materials.py @@ -17,6 +17,7 @@ if TYPE_CHECKING: from ansys.dpf.core.fields_container import FieldsContainer + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer from ansys.dpf.core.streams_container import StreamsContainer @@ -191,7 +192,7 @@ def __init__(self, op: Operator): enrich_materials._spec().input_pin(1), 1, op, -1 ) self._inputs.append(self._streams) - self._streams_mapping: Input = Input( + self._streams_mapping: Input[PropertyFieldsContainer] = Input( enrich_materials._spec().input_pin(2), 2, op, -1 ) self._inputs.append(self._streams_mapping) @@ -235,7 +236,7 @@ def streams(self) -> Input[StreamsContainer | FieldsContainer]: return self._streams @property - def streams_mapping(self) -> Input: + def streams_mapping(self) -> Input[PropertyFieldsContainer]: r"""Allows to connect streams_mapping input to the operator. Returns diff --git a/src/ansys/dpf/core/operators/logic/identical_pfc.py b/src/ansys/dpf/core/operators/logic/identical_pfc.py index d190d9596f4..1d56d756217 100644 --- a/src/ansys/dpf/core/operators/logic/identical_pfc.py +++ b/src/ansys/dpf/core/operators/logic/identical_pfc.py @@ -5,6 +5,7 @@ """ from __future__ import annotations +from typing import TYPE_CHECKING from warnings import warn from ansys.dpf.core.dpf_operator import Operator @@ -14,6 +15,9 @@ from ansys.dpf.core.config import Config from ansys.dpf.core.server_types import AnyServerType +if TYPE_CHECKING: + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer + class identical_pfc(Operator): r"""Checks if two property_fields_container are identical. @@ -172,17 +176,17 @@ class InputsIdenticalPfc(_Inputs): def __init__(self, op: Operator): super().__init__(identical_pfc._spec().inputs, op) - self._property_fields_containerA: Input = Input( + self._property_fields_containerA: Input[PropertyFieldsContainer] = Input( identical_pfc._spec().input_pin(0), 0, op, -1 ) self._inputs.append(self._property_fields_containerA) - self._property_fields_containerB: Input = Input( + self._property_fields_containerB: Input[PropertyFieldsContainer] = Input( identical_pfc._spec().input_pin(1), 1, op, -1 ) self._inputs.append(self._property_fields_containerB) @property - def property_fields_containerA(self) -> Input: + def property_fields_containerA(self) -> Input[PropertyFieldsContainer]: r"""Allows to connect property_fields_containerA input to the operator. Returns @@ -201,7 +205,7 @@ def property_fields_containerA(self) -> Input: return self._property_fields_containerA @property - def property_fields_containerB(self) -> Input: + def property_fields_containerB(self) -> Input[PropertyFieldsContainer]: r"""Allows to connect property_fields_containerB input to the operator. Returns diff --git a/src/ansys/dpf/core/operators/result/mapdl_split_to_acmo_facet_indices.py b/src/ansys/dpf/core/operators/result/mapdl_split_to_acmo_facet_indices.py index 2fff06dd8cf..167c25dd089 100644 --- a/src/ansys/dpf/core/operators/result/mapdl_split_to_acmo_facet_indices.py +++ b/src/ansys/dpf/core/operators/result/mapdl_split_to_acmo_facet_indices.py @@ -17,6 +17,7 @@ if TYPE_CHECKING: from ansys.dpf.core.fields_container import FieldsContainer + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer class mapdl_split_to_acmo_facet_indices(Operator): @@ -182,9 +183,9 @@ def __init__(self, op: Operator): mapdl_split_to_acmo_facet_indices._spec().input_pin(0), 0, op, -1 ) self._inputs.append(self._fields_container) - self._property_fields_container_element_types: Input = Input( - mapdl_split_to_acmo_facet_indices._spec().input_pin(1), 1, op, -1 - ) + self._property_fields_container_element_types: Input[ + PropertyFieldsContainer + ] = Input(mapdl_split_to_acmo_facet_indices._spec().input_pin(1), 1, op, -1) self._inputs.append(self._property_fields_container_element_types) @property @@ -209,7 +210,7 @@ def fields_container(self) -> Input[FieldsContainer]: return self._fields_container @property - def property_fields_container_element_types(self) -> Input: + def property_fields_container_element_types(self) -> Input[PropertyFieldsContainer]: r"""Allows to connect property_fields_container_element_types input to the operator. It should only have the 'facet' label. For each facet, it stores a PropertyField with the element types of the corresponding elements.The scoping should be the same as the scoping of the corresponding Field in input 0. diff --git a/src/ansys/dpf/core/operators/scoping/rescope_property_field.py b/src/ansys/dpf/core/operators/scoping/rescope_property_field.py index 31970043e91..c2e31bdabe7 100644 --- a/src/ansys/dpf/core/operators/scoping/rescope_property_field.py +++ b/src/ansys/dpf/core/operators/scoping/rescope_property_field.py @@ -18,6 +18,7 @@ if TYPE_CHECKING: from ansys.dpf.core.property_field import PropertyField + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer from ansys.dpf.core.scoping import Scoping @@ -187,7 +188,7 @@ class InputsRescopePropertyField(_Inputs): def __init__(self, op: Operator): super().__init__(rescope_property_field._spec().inputs, op) - self._fields: Input[PropertyField] = Input( + self._fields: Input[PropertyFieldsContainer | PropertyField] = Input( rescope_property_field._spec().input_pin(0), 0, op, -1 ) self._inputs.append(self._fields) @@ -201,7 +202,7 @@ def __init__(self, op: Operator): self._inputs.append(self._default_value) @property - def fields(self) -> Input[PropertyField]: + def fields(self) -> Input[PropertyFieldsContainer | PropertyField]: r"""Allows to connect fields input to the operator. Returns diff --git a/src/ansys/dpf/core/operators/utility/extract_scoping.py b/src/ansys/dpf/core/operators/utility/extract_scoping.py index 8dea62a8e47..db4a7ef3a76 100644 --- a/src/ansys/dpf/core/operators/utility/extract_scoping.py +++ b/src/ansys/dpf/core/operators/utility/extract_scoping.py @@ -23,6 +23,7 @@ from ansys.dpf.core.meshed_region import MeshedRegion from ansys.dpf.core.meshes_container import MeshesContainer from ansys.dpf.core.property_field import PropertyField + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer from ansys.dpf.core.scoping import Scoping from ansys.dpf.core.scopings_container import ScopingsContainer from ansys.dpf.core.string_field import StringField @@ -196,6 +197,7 @@ def __init__(self, op: Operator): Field | FieldsContainer | PropertyField + | PropertyFieldsContainer | CustomTypeField | StringField | Scoping @@ -216,6 +218,7 @@ def field_or_fields_container( Field | FieldsContainer | PropertyField + | PropertyFieldsContainer | CustomTypeField | StringField | Scoping diff --git a/src/ansys/dpf/core/operators/utility/merge_property_fields.py b/src/ansys/dpf/core/operators/utility/merge_property_fields.py index 241b147c099..908abda8f57 100644 --- a/src/ansys/dpf/core/operators/utility/merge_property_fields.py +++ b/src/ansys/dpf/core/operators/utility/merge_property_fields.py @@ -17,6 +17,7 @@ if TYPE_CHECKING: from ansys.dpf.core.property_field import PropertyField + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer class merge_property_fields(Operator): @@ -187,11 +188,11 @@ def __init__(self, op: Operator): merge_property_fields._spec().input_pin(-201), -201, op, -1 ) self._inputs.append(self._naive_merge) - self._property_fields1: Input[PropertyField] = Input( + self._property_fields1: Input[PropertyField | PropertyFieldsContainer] = Input( merge_property_fields._spec().input_pin(0), 0, op, 0 ) self._inputs.append(self._property_fields1) - self._property_fields2: Input[PropertyField] = Input( + self._property_fields2: Input[PropertyField | PropertyFieldsContainer] = Input( merge_property_fields._spec().input_pin(1), 1, op, 1 ) self._inputs.append(self._property_fields2) @@ -218,7 +219,7 @@ def naive_merge(self) -> Input[bool]: return self._naive_merge @property - def property_fields1(self) -> Input[PropertyField]: + def property_fields1(self) -> Input[PropertyField | PropertyFieldsContainer]: r"""Allows to connect property_fields1 input to the operator. Either a property fields container, a vector of property fields to merge or property fields from pin 0 to ... @@ -239,7 +240,7 @@ def property_fields1(self) -> Input[PropertyField]: return self._property_fields1 @property - def property_fields2(self) -> Input[PropertyField]: + def property_fields2(self) -> Input[PropertyField | PropertyFieldsContainer]: r"""Allows to connect property_fields2 input to the operator. Either a property fields container, a vector of property fields to merge or property fields from pin 0 to ... diff --git a/src/ansys/dpf/core/operators/utility/merge_weighted_fields_containers.py b/src/ansys/dpf/core/operators/utility/merge_weighted_fields_containers.py index eb1d181e5de..5dff318e322 100644 --- a/src/ansys/dpf/core/operators/utility/merge_weighted_fields_containers.py +++ b/src/ansys/dpf/core/operators/utility/merge_weighted_fields_containers.py @@ -17,6 +17,7 @@ if TYPE_CHECKING: from ansys.dpf.core.fields_container import FieldsContainer + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer class merge_weighted_fields_containers(Operator): @@ -36,11 +37,9 @@ class merge_weighted_fields_containers(Operator): A vector of fields containers to merge or fields containers from pin 0 to ... fields_containers2: FieldsContainer A vector of fields containers to merge or fields containers from pin 0 to ... - weights1: Class Dataprocessing::Dpftypecollection<Class - Dataprocessing::Cpropertyfield> + weights1: PropertyFieldsContainer Weights to apply to each field from pin 1000 to ... - weights2: Class Dataprocessing::Dpftypecollection<Class - Dataprocessing::Cpropertyfield> + weights2: PropertyFieldsContainer Weights to apply to each field from pin 1000 to ... Outputs @@ -65,9 +64,9 @@ class merge_weighted_fields_containers(Operator): >>> op.inputs.fields_containers1.connect(my_fields_containers1) >>> my_fields_containers2 = dpf.FieldsContainer() >>> op.inputs.fields_containers2.connect(my_fields_containers2) - >>> my_weights1 = dpf.Class Dataprocessing::Dpftypecollection<Class Dataprocessing::Cpropertyfield>() + >>> my_weights1 = dpf.PropertyFieldsContainer() >>> op.inputs.weights1.connect(my_weights1) - >>> my_weights2 = dpf.Class Dataprocessing::Dpftypecollection<Class Dataprocessing::Cpropertyfield>() + >>> my_weights2 = dpf.PropertyFieldsContainer() >>> op.inputs.weights2.connect(my_weights2) >>> # Instantiate operator and connect inputs in one line @@ -254,9 +253,9 @@ class InputsMergeWeightedFieldsContainers(_Inputs): >>> op.inputs.fields_containers1.connect(my_fields_containers1) >>> my_fields_containers2 = dpf.FieldsContainer() >>> op.inputs.fields_containers2.connect(my_fields_containers2) - >>> my_weights1 = dpf.Class Dataprocessing::Dpftypecollection<Class Dataprocessing::Cpropertyfield>() + >>> my_weights1 = dpf.PropertyFieldsContainer() >>> op.inputs.weights1.connect(my_weights1) - >>> my_weights2 = dpf.Class Dataprocessing::Dpftypecollection<Class Dataprocessing::Cpropertyfield>() + >>> my_weights2 = dpf.PropertyFieldsContainer() >>> op.inputs.weights2.connect(my_weights2) """ @@ -282,11 +281,11 @@ def __init__(self, op: Operator): merge_weighted_fields_containers._spec().input_pin(1), 1, op, 1 ) self._inputs.append(self._fields_containers2) - self._weights1: Input = Input( + self._weights1: Input[PropertyFieldsContainer] = Input( merge_weighted_fields_containers._spec().input_pin(1000), 1000, op, 0 ) self._inputs.append(self._weights1) - self._weights2: Input = Input( + self._weights2: Input[PropertyFieldsContainer] = Input( merge_weighted_fields_containers._spec().input_pin(1001), 1001, op, 1 ) self._inputs.append(self._weights2) @@ -397,7 +396,7 @@ def fields_containers2(self) -> Input[FieldsContainer]: return self._fields_containers2 @property - def weights1(self) -> Input: + def weights1(self) -> Input[PropertyFieldsContainer]: r"""Allows to connect weights1 input to the operator. Weights to apply to each field from pin 1000 to ... @@ -418,7 +417,7 @@ def weights1(self) -> Input: return self._weights1 @property - def weights2(self) -> Input: + def weights2(self) -> Input[PropertyFieldsContainer]: r"""Allows to connect weights2 input to the operator. Weights to apply to each field from pin 1000 to ... diff --git a/src/ansys/dpf/core/operators/utility/propertyfield_get_attribute.py b/src/ansys/dpf/core/operators/utility/propertyfield_get_attribute.py index e60ce4de25c..838fc1b8d5f 100644 --- a/src/ansys/dpf/core/operators/utility/propertyfield_get_attribute.py +++ b/src/ansys/dpf/core/operators/utility/propertyfield_get_attribute.py @@ -18,6 +18,7 @@ if TYPE_CHECKING: from ansys.dpf.core.property_field import PropertyField + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer class propertyfield_get_attribute(Operator): @@ -173,7 +174,7 @@ class InputsPropertyfieldGetAttribute(_Inputs): def __init__(self, op: Operator): super().__init__(propertyfield_get_attribute._spec().inputs, op) - self._property_field: Input[PropertyField] = Input( + self._property_field: Input[PropertyField | PropertyFieldsContainer] = Input( propertyfield_get_attribute._spec().input_pin(0), 0, op, -1 ) self._inputs.append(self._property_field) @@ -183,7 +184,7 @@ def __init__(self, op: Operator): self._inputs.append(self._property_name) @property - def property_field(self) -> Input[PropertyField]: + def property_field(self) -> Input[PropertyField | PropertyFieldsContainer]: r"""Allows to connect property_field input to the operator. Returns From 5442ba739237b3204acf057f09e22b6e5c40a71f Mon Sep 17 00:00:00 2001 From: Muhammed Adedigba <68085496+moe-ad@users.noreply.github.com> Date: Thu, 11 Dec 2025 10:07:18 +0100 Subject: [PATCH 25/27] fix: suggestions from code review Co-authored-by: Paul Profizi <100710998+PProfizi@users.noreply.github.com> --- src/ansys/dpf/core/property_fields_container.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_container.py index 4ca97bc14bb..7f7cdfbdf43 100644 --- a/src/ansys/dpf/core/property_fields_container.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -33,9 +33,9 @@ class PropertyFieldsContainer(Collection["property_field.PropertyField"]): - """Represents a property fields container, which contains property fields. + """Represents a property fields container, which is a collection of property fields. - A property fields container is a set of property fields ordered by labels and IDs. + A property fields container is a collection of property fields ordered by labels and IDs. Each property field in the collection has an ID for each label, allowing flexible organization and retrieval of property fields based on various criteria. From e0c70b39d18f55fd06bebe52dec6c083ded642ea Mon Sep 17 00:00:00 2001 From: moe-ad Date: Thu, 11 Dec 2025 10:19:33 +0100 Subject: [PATCH 26/27] fix: review suggestions and update conf.py --- doc/source/conf.py | 1 - src/ansys/dpf/core/property_fields_container.py | 11 +++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 35f0b64975c..01773e85243 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -104,7 +104,6 @@ "*/gate/*", "*/gatebin/*", "*/grpc/*", - "*/property_fields_container.py" ] # -- General configuration --------------------------------------------------- diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_container.py index 7f7cdfbdf43..76d74a0c2cf 100644 --- a/src/ansys/dpf/core/property_fields_container.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -28,9 +28,16 @@ from __future__ import annotations +from optparse import Option +from typing import TYPE_CHECKING, Optional + from ansys.dpf.core import property_field from ansys.dpf.core.collection import Collection +if TYPE_CHECKING: + from ansys.dpf.core.property_fields_container import PropertyFieldsContainer + from ansys.dpf.core.server_types import AnyServerType + class PropertyFieldsContainer(Collection["property_field.PropertyField"]): """Represents a property fields container, which is a collection of property fields. @@ -67,8 +74,8 @@ class PropertyFieldsContainer(Collection["property_field.PropertyField"]): def __init__( self, - property_fields_container=None, - server=None, + property_fields_container: Optional[PropertyFieldsContainer] = None, + server: Optional[AnyServerType] = None, entries_type: type = property_field.PropertyField, ): """Initialize a property fields container.""" From 65e8bc164ed3cd59b831139036883d1d42b27988 Mon Sep 17 00:00:00 2001 From: moe-ad Date: Thu, 11 Dec 2025 10:21:33 +0100 Subject: [PATCH 27/27] fix: remove IDE autoimport --- src/ansys/dpf/core/property_fields_container.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ansys/dpf/core/property_fields_container.py b/src/ansys/dpf/core/property_fields_container.py index 76d74a0c2cf..28ff78ba68e 100644 --- a/src/ansys/dpf/core/property_fields_container.py +++ b/src/ansys/dpf/core/property_fields_container.py @@ -28,7 +28,6 @@ from __future__ import annotations -from optparse import Option from typing import TYPE_CHECKING, Optional from ansys.dpf.core import property_field