diff --git a/pyproject.toml b/pyproject.toml index 041799d2fd..dbbe2547e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,7 @@ build-backend = "flit_core.buildapi" [project] # Check https://flit.readthedocs.io/en/latest/pyproject_toml.html for all available sections name = "ansys-edb-core" -version = "0.2.0.dev3" +version = "0.2.0.dev4" description = "A python wrapper for Ansys Edb service" readme = "README.rst" requires-python = ">=3.8" @@ -25,7 +25,7 @@ classifiers = [ dependencies = [ - "ansys-api-edb==0.2.dev5", + "ansys-api-edb==0.2.dev6", "protobuf>=3.19.3,<5", "grpcio>=1.44.0", "Django>=4.2.16" diff --git a/src/ansys/edb/core/definition/component_def.py b/src/ansys/edb/core/definition/component_def.py index dc83476ac4..6317bfc1e3 100644 --- a/src/ansys/edb/core/definition/component_def.py +++ b/src/ansys/edb/core/definition/component_def.py @@ -101,7 +101,7 @@ def component_models(self): This property is read-only. """ objs = self.__stub.GetComponentModels(self.msg).items - return map_list(objs, component_model.ComponentModel) + return map_list(objs, lambda msg: component_model.ComponentModel(msg).cast()) @property def component_pins(self): diff --git a/src/ansys/edb/core/definition/component_model.py b/src/ansys/edb/core/definition/component_model.py index fd3ba2fb66..4329e14209 100644 --- a/src/ansys/edb/core/definition/component_model.py +++ b/src/ansys/edb/core/definition/component_model.py @@ -1,4 +1,7 @@ """Component model definition.""" +from enum import Enum + +from ansys.api.edb.v1.component_model_pb2 import ComponentModelType as pb_comp_model_Type from ansys.api.edb.v1.component_model_pb2_grpc import ( ComponentModelServiceStub, DynamicLinkComponentModelServiceStub, @@ -10,6 +13,14 @@ from ansys.edb.core.session import StubAccessor, StubType +class ComponentModelType(Enum): + """Enum representing component model types.""" + + N_PORT = pb_comp_model_Type.N_PORT + DYNAMIC_LINK = pb_comp_model_Type.DYNAMIC_LINK + UNKNOWN_COMPONENT_MODEL_TYPE = pb_comp_model_Type.UNKNOWN_MODEL_TYPE + + class ComponentModel(ObjBase): """Represents a component model.""" @@ -42,7 +53,7 @@ def find_by_name(cls, comp_def, value): """ return ComponentModel( cls.__stub.FindByName(messages.string_property_message(comp_def, value)) - ) + ).cast() @classmethod def find_by_id(cls, comp_def, value): @@ -60,7 +71,51 @@ def find_by_id(cls, comp_def, value): ComponentModel Component model that is found, ``None`` otherwise. """ - return ComponentModel(cls.__stub.FindById(messages.int_proprty_message(comp_def, value))) + return ComponentModel( + cls.__stub.FindById(messages.int_property_message(comp_def, value)) + ).cast() + + @property + def name(self) -> str: + """:obj:`str`: The name of the component model. + + This property is read-only. + """ + return self.__stub.GetName(self.msg).value + + @property + def component_model_type(self) -> ComponentModelType: + """:class:`.ComponentModelType`: The type of the component model. + + This property is read-only. + """ + return ComponentModelType(self.__stub.GetType(self.msg).type) + + @property + def component_model_id(self) -> int: + """:obj:`int`: The id of the component model. + + This property is read-only. + """ + return self.__stub.GetId(self.msg).value + + def cast(self) -> "ComponentModel": + """Cast the component model object to the correct concrete type. + + Returns + ------- + .ComponentModel + """ + comp_model_type = ( + ComponentModelType.UNKNOWN_COMPONENT_MODEL_TYPE + if self.is_null + else self.component_model_type + ) + if comp_model_type == ComponentModelType.N_PORT: + return NPortComponentModel(self.msg) + elif comp_model_type == ComponentModelType.DYNAMIC_LINK: + return DynamicLinkComponentModel(self.msg) + return ComponentModel(self.msg) class NPortComponentModel(ComponentModel): diff --git a/src/ansys/edb/core/definition/padstack_def_data.py b/src/ansys/edb/core/definition/padstack_def_data.py index 54a147d925..80868bda17 100644 --- a/src/ansys/edb/core/definition/padstack_def_data.py +++ b/src/ansys/edb/core/definition/padstack_def_data.py @@ -189,13 +189,15 @@ def get_pad_parameters(self, layer, pad_type): Value(message.generic.offset_y), Value(message.generic.rotation), ) - else: + elif message.HasField("polygon"): return ( parser.to_polygon_data(message.polygon.fp), Value(message.polygon.offset_x), Value(message.polygon.offset_y), Value(message.polygon.rotation), ) + else: + return () def set_pad_parameters( self, layer, pad_type, offset_x, offset_y, rotation, type_geom=None, sizes=None, fp=None diff --git a/src/ansys/edb/core/hierarchy/group.py b/src/ansys/edb/core/hierarchy/group.py index b3a31dc4a7..d115336bdf 100644 --- a/src/ansys/edb/core/hierarchy/group.py +++ b/src/ansys/edb/core/hierarchy/group.py @@ -6,6 +6,7 @@ from ansys.edb.core.edb_defs import LayoutObjType from ansys.edb.core.hierarchy.hierarchy_obj import HierarchyObj from ansys.edb.core.inner import messages +from ansys.edb.core.inner.utils import query_lyt_object_collection from ansys.edb.core.session import StubAccessor, StubType @@ -113,7 +114,10 @@ def members(self): This property is read-only. """ - from ansys.edb.core.inner import factory - - objs = self.__stub.GetMembers(self.msg).items - return [factory.create_conn_obj(co) for co in objs] + return query_lyt_object_collection( + self, + LayoutObjType.INVALID_LAYOUT_OBJ, + self.__stub.GetMembers, + self.__stub.StreamMembers, + False, + ) diff --git a/src/ansys/edb/core/inner/conn_obj.py b/src/ansys/edb/core/inner/conn_obj.py index 6b99d9ffc9..1e30e16cb5 100644 --- a/src/ansys/edb/core/inner/conn_obj.py +++ b/src/ansys/edb/core/inner/conn_obj.py @@ -3,6 +3,7 @@ from ansys.edb.core.edb_defs import LayoutObjType from ansys.edb.core.inner import layout_obj, messages +from ansys.edb.core.inner.factory import create_lyt_obj from ansys.edb.core.layout import mcad_model as mm from ansys.edb.core.session import ConnectableServiceStub, StubAccessor, StubType @@ -48,6 +49,15 @@ def get_client_prim_type_from_class(): return client_obj return cls(None) + def cast(self): + """Cast the ConnObj object to the correct concrete type. + + Returns + ------- + .ConnObj + """ + return create_lyt_obj(self.msg, self.obj_type) + @property def obj_type(self): """:class:`LayoutObjType `: Layout object type. diff --git a/src/ansys/edb/core/inner/factory.py b/src/ansys/edb/core/inner/factory.py index 885e9ba032..ce991b3468 100644 --- a/src/ansys/edb/core/inner/factory.py +++ b/src/ansys/edb/core/inner/factory.py @@ -43,7 +43,7 @@ def _initialize_type_creator_params_dict(): LayoutObjType.EXTENDED_NET: _CreatorParams(ExtendedNet), LayoutObjType.DIFFERENTIAL_PAIR: _CreatorParams(DifferentialPair), LayoutObjType.NET: _CreatorParams(Net), - LayoutObjType.INVALID_LAYOUT_OBJ: _CreatorParams(ConnObj), + LayoutObjType.INVALID_LAYOUT_OBJ: _CreatorParams(ConnObj, True), } return _type_creator_params_dict @@ -158,4 +158,4 @@ def create_conn_obj(msg): ------- ansys.edb.core.inner.ConnObj """ - return create_lyt_obj(msg, create_lyt_obj(msg, LayoutObjType.INVALID_LAYOUT_OBJ).obj_type) + return create_lyt_obj(msg, LayoutObjType.INVALID_LAYOUT_OBJ) diff --git a/src/ansys/edb/core/inner/parser.py b/src/ansys/edb/core/inner/parser.py index ea170ec31b..b86e71e0be 100644 --- a/src/ansys/edb/core/inner/parser.py +++ b/src/ansys/edb/core/inner/parser.py @@ -507,4 +507,4 @@ def _to_mesh_op(message): def _to_string_dict(message): """Convert a message to a dictionary of strings.""" - return {key: value for (key, value) in message.string_map} + return {key: value for (key, value) in message.string_map.items()} diff --git a/src/ansys/edb/core/inner/rpc_info.py b/src/ansys/edb/core/inner/rpc_info.py index 6afd2db569..10e6975a5c 100644 --- a/src/ansys/edb/core/inner/rpc_info.py +++ b/src/ansys/edb/core/inner/rpc_info.py @@ -197,6 +197,9 @@ def invalidates_cache(self): "GetReferenceFile": _RpcInfo(cache=True), "FindByName": _RpcInfo(cache=True), "FindById": _RpcInfo(cache=True), + "GetName": _RpcInfo(cache=True), + "GetType": _RpcInfo(cache=True), + "GetId": _RpcInfo(cache=True), }, "ansys.api.edb.v1.NPortComponentModelService": { "Create": _RpcInfo(buffer=True, returns_future=True, write_no_cache_invalidation=True) @@ -1045,6 +1048,7 @@ def invalidates_cache(self): "GetParameters": _RpcInfo(cache=True), "SetParameters": _RpcInfo(buffer=True), "Render": _RpcInfo(cache=True), + "GetPolygonData": _RpcInfo(cache=True), }, "ansys.api.edb.v1.RLCComponentPropertyService": { "Create": _RpcInfo(buffer=True, returns_future=True, write_no_cache_invalidation=True), diff --git a/src/ansys/edb/core/primitive/padstack_instance.py b/src/ansys/edb/core/primitive/padstack_instance.py index 543b5f91c8..d2a6f2dbda 100644 --- a/src/ansys/edb/core/primitive/padstack_instance.py +++ b/src/ansys/edb/core/primitive/padstack_instance.py @@ -200,7 +200,8 @@ def set_layer_range(self, top_layer, bottom_layer): @property def solderball_layer(self): """:class:`.Layer`: Solderball layer of the padstack instance.""" - return Layer(self.__stub.GetSolderBallLayer(self.msg)).cast() + sb_layer = Layer(self.__stub.GetSolderBallLayer(self.msg)) + return sb_layer if sb_layer.is_null() else sb_layer.cast() @solderball_layer.setter def solderball_layer(self, solderball_layer): diff --git a/src/ansys/edb/core/primitive/rectangle.py b/src/ansys/edb/core/primitive/rectangle.py index 2a12e02e77..61614924e5 100644 --- a/src/ansys/edb/core/primitive/rectangle.py +++ b/src/ansys/edb/core/primitive/rectangle.py @@ -162,13 +162,14 @@ def can_be_zone_primitive(self): return True @property + @parser.to_polygon_data def polygon_data(self): """:class:`.PolygonData`: \ Polygon data object of the rectangle. This property is read-only. """ - return Rectangle.render(*self.get_parameters()) + return self.__stub.GetPolygonData(self.msg) @classmethod @parser.to_polygon_data diff --git a/src/ansys/edb/core/simulation_setup/simulation_setup.py b/src/ansys/edb/core/simulation_setup/simulation_setup.py index bc2ffa9ae2..e109b3110a 100644 --- a/src/ansys/edb/core/simulation_setup/simulation_setup.py +++ b/src/ansys/edb/core/simulation_setup/simulation_setup.py @@ -370,7 +370,13 @@ def _msg_to_sweep_data(msg): """Create a ``SweepData`` from a ``SweepDataMessage``.""" freq_str_params = msg.frequency_string.split() sweep_data = SweepData( - msg.name, freq_str_params[0], freq_str_params[1], freq_str_params[2], freq_str_params[3] + msg.name, + FrequencyData( + Distribution[freq_str_params[0]], + freq_str_params[1], + freq_str_params[2], + freq_str_params[3], + ), ) sweep_data.enabled = msg.enabled sweep_data.type = FreqSweepType(msg.type) diff --git a/src/ansys/edb/core/simulation_setup/siwave_simulation_settings.py b/src/ansys/edb/core/simulation_setup/siwave_simulation_settings.py index 31a7c2edd5..8cf5175229 100644 --- a/src/ansys/edb/core/simulation_setup/siwave_simulation_settings.py +++ b/src/ansys/edb/core/simulation_setup/siwave_simulation_settings.py @@ -114,7 +114,7 @@ def si_slider_pos(self): @si_slider_pos.setter def si_slider_pos(self, si_slider_pos): - self.__stub.SetSISliderPos(messages.int_property_message(self, si_slider_pos)) + self.__stub.SetSISliderPos(messages.uint64_property_message(self, si_slider_pos)) @property def pi_slider_pos(self): @@ -123,7 +123,7 @@ def pi_slider_pos(self): @pi_slider_pos.setter def pi_slider_pos(self, pi_slider_pos): - self.__stub.SetPISliderPos(messages.int_property_message(self, pi_slider_pos)) + self.__stub.SetPISliderPos(messages.uint64_property_message(self, pi_slider_pos)) class SIWaveAdvancedSettings(SimulationSettingsBase): @@ -388,7 +388,7 @@ def dc_slider_pos(self): @dc_slider_pos.setter def dc_slider_pos(self, dc_slider_pos): - self.__stub.SetDCSliderPos(messages.int_property_message(self, dc_slider_pos)) + self.__stub.SetDCSliderPos(messages.uint64_property_message(self, dc_slider_pos)) class SIWaveDCAdvancedSettings(SimulationSettingsBase): @@ -449,7 +449,7 @@ def max_num_passes(self): @max_num_passes.setter def max_num_passes(self, max_num_passes): - self.__stub.SetMaxNumPasses(messages.int_property_message(self, max_num_passes)) + self.__stub.SetMaxNumPasses(messages.uint64_property_message(self, max_num_passes)) @property def min_num_passes(self): @@ -458,7 +458,7 @@ def min_num_passes(self): @min_num_passes.setter def min_num_passes(self, min_num_passes): - self.__stub.SetMinNumPasses(messages.int_property_message(self, min_num_passes)) + self.__stub.SetMinNumPasses(messages.uint64_property_message(self, min_num_passes)) @property def percent_local_refinement(self): @@ -468,7 +468,7 @@ def percent_local_refinement(self): @percent_local_refinement.setter def percent_local_refinement(self, percent_local_refinement): self.__stub.SetPercentLocalRefinement( - messages.int_property_message(self, percent_local_refinement) + messages.uint64_property_message(self, percent_local_refinement) ) @property @@ -523,7 +523,7 @@ def num_bw_sides(self): @num_bw_sides.setter def num_bw_sides(self, num_bw_sides): - self.__stub.SetNumBwSides(messages.int_property_message(self, num_bw_sides)) + self.__stub.SetNumBwSides(messages.uint64_property_message(self, num_bw_sides)) @property def num_via_sides(self): @@ -532,7 +532,7 @@ def num_via_sides(self): @num_via_sides.setter def num_via_sides(self, num_via_sides): - self.__stub.SetNumViaSides(messages.int_property_message(self, num_via_sides)) + self.__stub.SetNumViaSides(messages.uint64_property_message(self, num_via_sides)) class SIWaveSParameterSettings(SimulationSettingsBase): diff --git a/src/ansys/edb/core/terminal/bundle_terminal.py b/src/ansys/edb/core/terminal/bundle_terminal.py index 7419737bc7..857cc10d65 100644 --- a/src/ansys/edb/core/terminal/bundle_terminal.py +++ b/src/ansys/edb/core/terminal/bundle_terminal.py @@ -28,7 +28,7 @@ def create(cls, terminals): @property def terminals(self): """:obj:`list` of Terminal: All terminals grouped in the terminal.""" - return [Terminal(msg).cast() for msg in self.__stub.GetTerminals(self.msg)] + return [Terminal(msg).cast() for msg in self.__stub.GetTerminals(self.msg).items] def ungroup(self): """Delete the grouping.""" diff --git a/src/ansys/edb/core/terminal/edge_terminal.py b/src/ansys/edb/core/terminal/edge_terminal.py index cabc658042..938b74ee88 100644 --- a/src/ansys/edb/core/terminal/edge_terminal.py +++ b/src/ansys/edb/core/terminal/edge_terminal.py @@ -46,7 +46,7 @@ def _create(cls, **params): @property def _type(self): - return EdgeType(self.__stub.GetType(self.msg)) + return EdgeType(self.__stub.GetEdgeType(self.msg).t) @property def _params(self): @@ -163,7 +163,7 @@ def create(cls, layout, name, edges, net=None, is_ref=False): @property def edges(self): """:obj:`list` of :class:`.Edge`: All edges on the terminal.""" - return [Edge(msg).cast() for msg in self.__stub.GetEdges(self.msg)] + return [Edge(msg).cast() for msg in self.__stub.GetEdges(self.msg).items] @edges.setter def edges(self, edges): diff --git a/tests/mock/test_terminals.py b/tests/mock/test_terminals.py index ba78cb614b..7f6de9f758 100644 --- a/tests/mock/test_terminals.py +++ b/tests/mock/test_terminals.py @@ -1,7 +1,7 @@ import ansys.api.edb.v1.layer_pb2 as layer_pb2 import ansys.api.edb.v1.term_pb2 as term_pb2 from utils.fixtures import * # noqa -from utils.test_utils import create_edb_obj_msgs, equals +from utils.test_utils import create_edb_obj_collection_msg, equals from ansys.edb.core.geometry.point_data import PointData from ansys.edb.core.inner import messages @@ -68,7 +68,7 @@ def test_bundle_terminal_get_terminals(mocked_stub, bundle_terminal, term_type, get_terminals = mocked_stub( bundle_terminal_mod, bundle_terminal_mod.BundleTerminal ).GetTerminals - get_terminals.return_value = expected = create_edb_obj_msgs(2) + get_terminals.return_value = expected = create_edb_obj_collection_msg(2) get_params = mocked_stub(terminal_mod, terminal_mod.Terminal).GetParams get_params.return_value = term_pb2.TermParamsMessage(term_type=term_type) @@ -79,7 +79,7 @@ def test_bundle_terminal_get_terminals(mocked_stub, bundle_terminal, term_type, assert len(terms) == 2 for t in terms: assert isinstance(t, term_cls) - assert sorted([t.id for t in terms]) == sorted([msg.id for msg in expected]) + assert sorted([t.id for t in terms]) == sorted([msg.id for msg in expected.items]) def test_bundle_terminal_ungroup(mocked_stub, bundle_terminal):