Skip to content

Commit 32ec6c8

Browse files
authored
Merge branch 'master' into feat/add_available_qualifiers_to_result_info_str
2 parents 56d9279 + 99e8b4f commit 32ec6c8

File tree

8 files changed

+215
-47
lines changed

8 files changed

+215
-47
lines changed

src/ansys/dpf/core/any.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
from ansys.dpf.core import server as server_module
1212
from ansys.dpf.core import errors
1313
from ansys.dpf.core.common import type_to_internal_object_keyword
14+
from ansys.dpf.gate import any_abstract_api
1415

1516

1617
class Any:
@@ -55,6 +56,7 @@ def _type_to_new_from_get_as_method(any_dpf):
5556
generic_data_container,
5657
string_field,
5758
scoping,
59+
data_tree,
5860
)
5961

6062
return [
@@ -97,6 +99,11 @@ def _type_to_new_from_get_as_method(any_dpf):
9799
any_dpf._api.any_new_from_scoping,
98100
any_dpf._api.any_get_as_scoping,
99101
),
102+
(
103+
data_tree.DataTree,
104+
any_dpf._api.any_new_from_data_tree,
105+
any_dpf._api.any_get_as_data_tree,
106+
),
100107
]
101108

102109
@staticmethod
@@ -138,7 +145,7 @@ def new_from(obj, server=None):
138145
raise TypeError(f"{obj.__class__} is not currently supported by the Any class.")
139146

140147
@property
141-
def _api(self):
148+
def _api(self) -> any_abstract_api.AnyAbstractAPI:
142149
from ansys.dpf.gate import any_capi, any_grpcapi
143150

144151
if not self._api_instance:

src/ansys/dpf/core/data_tree.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,11 +482,108 @@ def get_as(self, name, type_to_return=types.string):
482482
out = DataTree(data_tree=obj, server=self._server)
483483
return out
484484

485+
def get_attribute_names(self):
486+
"""
487+
Returns a list of defined attribute names.
488+
489+
Returns
490+
-------
491+
list[str]
492+
493+
Examples
494+
--------
495+
>>> from ansys.dpf import core as dpf
496+
>>> data_tree = dpf.DataTree()
497+
>>> data_tree.add(id=3, qualities=["nice", "funny"], name="George")
498+
>>> data_tree.get_attribute_names()
499+
['id', 'name', 'qualities']
500+
"""
501+
coll_obj = collection.StringCollection(
502+
collection=self._api.dpf_data_tree_get_available_attributes_names_in_string_collection(
503+
self
504+
),
505+
server=self._server,
506+
)
507+
508+
return coll_obj.get_integral_entries()
509+
510+
def get_sub_tree_names(self):
511+
"""
512+
Returns a list of defined sub-tree names.
513+
514+
Returns
515+
-------
516+
list[str]
517+
518+
Examples
519+
--------
520+
>>> from ansys.dpf import core as dpf
521+
>>> data_tree = dpf.DataTree()
522+
>>> first_subtree = dpf.DataTree()
523+
>>> second_subtree = dpf.DataTree()
524+
>>> data_tree.add(first=first_subtree, second=second_subtree)
525+
>>> data_tree.get_sub_tree_names()
526+
['first', 'second']
527+
"""
528+
coll_obj = collection.StringCollection(
529+
collection=self._api.dpf_data_tree_get_available_sub_tree_names_in_string_collection(
530+
self
531+
),
532+
server=self._server,
533+
)
534+
535+
return coll_obj.get_integral_entries()
536+
537+
def __to_dict(self, dic):
538+
for attribute_name in self.get_attribute_names():
539+
dic[attribute_name] = self.get_as(attribute_name)
540+
541+
for sub_tree_name in self.get_sub_tree_names():
542+
sub_tree = self.get_as(sub_tree_name, types.data_tree)
543+
sub_dic = {}
544+
sub_tree.__to_dict(sub_dic)
545+
dic[sub_tree_name] = sub_dic
546+
547+
def to_dict(self):
548+
"""
549+
Returns a dictionary representation of the DataTree
550+
551+
Returns
552+
-------
553+
dict
554+
555+
Examples
556+
--------
557+
>>> from ansys.dpf import core as dpf
558+
>>> data_tree = dpf.DataTree()
559+
>>> sub = dpf.DataTree()
560+
>>> sub.add(str="hello world")
561+
>>> data_tree.add(id=3, sub_tree=sub)
562+
>>> data_tree.to_dict()
563+
{'id': '3', 'sub_tree': {'str': 'hello world'}}
564+
"""
565+
dic = {}
566+
self.__to_dict(dic)
567+
568+
return dic
569+
485570
def __setattr__(self, key, value):
486571
if key == "_common_keys" or key in self._common_keys:
487572
return super.__setattr__(self, key, value)
488573
self.add({key: value})
489574

575+
def __str__(self):
576+
"""Describe the entity.
577+
578+
Returns
579+
-------
580+
str
581+
Description of the entity.
582+
"""
583+
from ansys.dpf.core.core import _description
584+
585+
return _description(self._internal_obj, self._server)
586+
490587
def __del__(self):
491588
try:
492589
# needs a proper deleter only when real datatree and not dict

src/ansys/dpf/core/generic_data_container.py

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
"""
77
import traceback
88
import warnings
9+
import builtins
910

1011
from ansys.dpf.core import server as server_module
1112
from ansys.dpf.core import errors
@@ -110,31 +111,14 @@ def get_property(self, property_name):
110111
"""
111112
any_ptr = self._api.generic_data_container_get_property_any(self, property_name)
112113
any_dpf = Any(any_ptr, self._server)
113-
output_type = self._type_to_output_method[self.get_property_description()[property_name]]
114-
return any_dpf.cast(output_type)
114+
output_type = self.get_property_description()[property_name]
115+
class_ = getattr(builtins, output_type, None)
116+
if class_ is None:
117+
from ansys.dpf import core
115118

116-
@property
117-
def _type_to_output_method(self):
118-
# Only the types in any.py need to be casted
119-
from ansys.dpf.core import (
120-
field,
121-
property_field,
122-
string_field,
123-
scoping,
124-
)
119+
class_ = getattr(core, output_type)
125120

126-
out = {
127-
"bool": bool,
128-
"int": int,
129-
"str": str,
130-
"float": float,
131-
"Field": field.Field,
132-
"PropertyField": property_field.PropertyField,
133-
"StringField": string_field.StringField,
134-
"Scoping": scoping.Scoping,
135-
"GenericDataContainer": GenericDataContainer,
136-
}
137-
return out
121+
return any_dpf.cast(class_)
138122

139123
def get_property_description(self):
140124
"""Get a dictionary description of properties by name and data type

src/ansys/dpf/core/mesh_info.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ def set_property(self, property_name, prop):
131131
return self.generic_data_container.set_property(property_name, prop)
132132

133133
@property
134-
def get_number_nodes(self):
134+
def number_nodes(self):
135135
"""
136136
Returns
137137
-------
@@ -142,7 +142,7 @@ def get_number_nodes(self):
142142
return self.generic_data_container.get_property("num_nodes")
143143

144144
@property
145-
def get_number_elements(self):
145+
def number_elements(self):
146146
"""
147147
Returns
148148
-------
@@ -153,7 +153,7 @@ def get_number_elements(self):
153153
return self.generic_data_container.get_property("num_elements")
154154

155155
@property
156-
def get_splittable_by(self):
156+
def splittable_by(self):
157157
"""
158158
Returns
159159
-------
@@ -164,7 +164,7 @@ def get_splittable_by(self):
164164
return self.generic_data_container.get_property("splittable_by")
165165

166166
@property
167-
def get_available_elem_types(self):
167+
def available_elem_types(self):
168168
"""
169169
Returns
170170
-------
@@ -174,22 +174,26 @@ def get_available_elem_types(self):
174174

175175
return self.generic_data_container.get_property("avalaible_elem_type")
176176

177-
def set_number_nodes(self, number_of_nodes):
177+
@number_nodes.setter
178+
def number_nodes(self, value):
178179
"""Set the number of nodes in the mesh"""
179180

180-
return self.generic_data_container.set_property("num_nodes", number_of_nodes)
181+
self.generic_data_container.set_property("num_nodes", value)
181182

182-
def set_number_elements(self, number_of_elements):
183+
@number_elements.setter
184+
def number_elements(self, value):
183185
"""Set the number of elements in the mesh"""
184186

185-
return self.generic_data_container.set_property("num_elements", number_of_elements)
187+
self.generic_data_container.set_property("num_elements", value)
186188

187-
def set_splittable_by(self, split):
189+
@splittable_by.setter
190+
def splittable_by(self, value):
188191
"""Set name of the properties according to which the mesh can be split by"""
189192

190-
return self.generic_data_container.set_property("splittable_by", split)
193+
self.generic_data_container.set_property("splittable_by", value)
191194

192-
def set_available_elem_types(self, available_elem_types):
195+
@available_elem_types.setter
196+
def available_elem_types(self, value):
193197
"""Set the available element types"""
194198

195-
return self.generic_data_container.set_property("avalaible_elem_type", available_elem_types)
199+
self.generic_data_container.set_property("avalaible_elem_type", value)

src/ansys/dpf/core/operator_specification.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,9 @@ def _fill_pins(self, binput, to_fill):
383383
]
384384

385385
pin_derived_class_type_name = ""
386-
if server_meet_version("7.0", self._server):
386+
if server_meet_version("7.0", self._server) and hasattr(
387+
self._api, "operator_specification_get_pin_derived_class_type_name"
388+
):
387389
pin_derived_class_type_name = (
388390
self._api.operator_specification_get_pin_derived_class_type_name(
389391
self, binput, i_pin
@@ -614,7 +616,9 @@ def inputs(self) -> dict:
614616
def inputs(self, val: dict):
615617
for key, value in val.items():
616618
list_types = integral_types.MutableListString(value.type_names)
617-
if server_meet_version("7.0", self._server):
619+
if server_meet_version("7.0", self._server) and hasattr(
620+
self._api, "operator_specification_set_pin_derived_class"
621+
):
618622
self._api.operator_specification_set_pin_derived_class(
619623
self,
620624
True,
@@ -655,7 +659,9 @@ def outputs(self) -> dict:
655659
def outputs(self, val: dict):
656660
for key, value in val.items():
657661
list_types = integral_types.MutableListString(value.type_names)
658-
if server_meet_version("7.0", self._server):
662+
if server_meet_version("7.0", self._server) and hasattr(
663+
self._api, "operator_specification_set_pin_derived_class"
664+
):
659665
self._api.operator_specification_set_pin_derived_class(
660666
self,
661667
False,

tests/test_data_tree.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ def test_read_from_txt_data_tree(server_type):
235235
assert data_tree.has("list_string")
236236

237237

238+
@conftest.raises_for_servers_version_under("4.0")
239+
def test_print_data_tree(server_type):
240+
data_tree = dpf.DataTree(server=server_type)
241+
with data_tree.to_fill() as to_fill:
242+
to_fill.int = 1
243+
to_fill.double = 1.0
244+
to_fill.string = "hello"
245+
to_fill.list_int = [1, 2]
246+
to_fill.list_double = [1.5, 2.5]
247+
to_fill.add(list_string=["hello", "bye"])
248+
assert str(data_tree) != ""
249+
250+
238251
@conftest.raises_for_servers_version_under("4.0")
239252
def test_sub_data_tree():
240253
data_tree = dpf.DataTree()
@@ -316,3 +329,48 @@ def test_unsupported_types_data_tree(server_type):
316329
data_tree.add(data1=[[1]])
317330
with pytest.raises(TypeError):
318331
data_tree.add(data1=(1, 2))
332+
333+
334+
@pytest.mark.skipif(
335+
not conftest.SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_7_0, reason="Available for servers >=7.0"
336+
)
337+
def test_list_attributes_data_tree(server_type):
338+
data_tree = dpf.DataTree(server=server_type)
339+
with data_tree.to_fill() as to_fill:
340+
to_fill.int = 1
341+
to_fill.double = 1.0
342+
to_fill.string = "hello"
343+
to_fill.list_int = [1, 2]
344+
to_fill.list_double = [1.5, 2.5]
345+
to_fill.add(list_string=["hello", "bye"])
346+
347+
attributes = data_tree.get_attribute_names()
348+
349+
assert ["double", "int", "list_double", "list_int", "list_string", "string"] == attributes
350+
351+
352+
@pytest.mark.skipif(
353+
not conftest.SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_7_0, reason="Available for servers >=7.0"
354+
)
355+
def test_list_attributes_recursive_data_tree(server_type):
356+
data_tree = dpf.DataTree(server=server_type)
357+
with data_tree.to_fill() as to_fill:
358+
to_fill.attribute01 = 1
359+
sub_tree01 = dpf.DataTree(server=server_type)
360+
with sub_tree01.to_fill() as to_fill01:
361+
to_fill01.attribute02 = 2
362+
to_fill.sub_tree01 = sub_tree01
363+
sub_tree02 = dpf.DataTree(server=server_type)
364+
to_fill.sub_tree02 = sub_tree02
365+
366+
attributes = data_tree.get_attribute_names()
367+
sub_trees = data_tree.get_sub_tree_names()
368+
369+
assert attributes == ["attribute01"]
370+
assert sub_trees == ["sub_tree01", "sub_tree02"]
371+
372+
dic = data_tree.to_dict()
373+
374+
assert ["attribute01", "sub_tree01", "sub_tree02"] == list(dic.keys())
375+
assert {"attribute02": "2"} == dic["sub_tree01"]
376+
assert {} == dic["sub_tree02"]

tests/test_generic_data_container.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,18 @@ def test_set_get_property_generic_data_container(server_type):
2424
assert entity.location == new_entity.location
2525

2626

27+
@pytest.mark.skipif(
28+
not SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_7_0, reason="Available for servers >=7.0"
29+
)
30+
def test_set_get_data_tree_generic_data_container(server_type):
31+
gdc = dpf.GenericDataContainer(server=server_type)
32+
entity = dpf.DataTree(server=server_type)
33+
entity.add(name="john")
34+
gdc.set_property("persons", entity)
35+
new_entity = gdc.get_property("persons")
36+
assert new_entity.get_as("name") == "john"
37+
38+
2739
@pytest.mark.skipif(
2840
not SERVERS_VERSION_GREATER_THAN_OR_EQUAL_TO_7_0, reason="Available for servers >=7.0"
2941
)

0 commit comments

Comments
 (0)