diff --git a/capella2polarion/converters/converter_config.py b/capella2polarion/converters/converter_config.py index 2725d73e..75e3c7b2 100644 --- a/capella2polarion/converters/converter_config.py +++ b/capella2polarion/converters/converter_config.py @@ -10,6 +10,7 @@ import yaml from capellambse.model import common, diagram +from capellambse_context_diagrams import filters as context_filters logger = logging.getLogger(__name__) @@ -296,7 +297,7 @@ def _force_dict( case list(): return {c: {} for c in config} case dict(): - return {k: v or {} for k, v in config.items()} + return _filter_converter_config(config) case _: raise TypeError("Unsupported Type") @@ -308,6 +309,47 @@ def add_prefix(polarion_type: str, prefix: str) -> str: return polarion_type +def _filter_converter_config( + config: dict[str, dict[str, t.Any]] +) -> dict[str, dict[str, t.Any]]: + custom_converters = ( + "include_pre_and_post_condition", + "linked_text_as_description", + "add_context_diagram", + "add_tree_diagram", + "add_jinja_fields", + "jinja_as_description", + ) + filtered_config = {} + for name, params in config.items(): + params = params or {} + if name not in custom_converters: + logger.error("Unknown converter in config %r", name) + continue + + if name in ("add_context_diagram", "add_tree_diagram"): + params = _filter_context_diagram_config(params) + + filtered_config[name] = params + + return filtered_config + + +def _filter_context_diagram_config( + config: dict[str, t.Any] +) -> dict[str, t.Any]: + converted_filters = [] + for filter_name in config.get("filters", []): + try: + converted_filters.append(getattr(context_filters, filter_name)) + except AttributeError: + logger.error("Unknown diagram filter in config %r", filter_name) + + if converted_filters: + config["filters"] = converted_filters + return config + + def _filter_links( c_type: str, links: list[LinkConfig], is_global: bool = False ): @@ -315,7 +357,7 @@ def _filter_links( c_class = diagram.Diagram else: if not (c_classes := common.find_wrapper(c_type)): - logger.error("Did not find any matching Wrapper for %s", c_type) + logger.error("Did not find any matching Wrapper for %r", c_type) return links c_class = c_classes[0] diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index fdf1662b..3166df03 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -519,10 +519,13 @@ def _add_context_diagram( self, converter_data: data_session.ConverterData, render_params: dict[str, t.Any] | None = None, + filters: list[str] | None = None, ) -> data_models.CapellaWorkItem: """Add a new custom field context diagram.""" assert converter_data.work_item, "No work item set yet" diagram = converter_data.capella_element.context_diagram + for filter in filters or []: + diagram.filters.add(filter) self._draw_additional_attributes_diagram( converter_data.work_item, @@ -538,10 +541,13 @@ def _add_tree_diagram( self, converter_data: data_session.ConverterData, render_params: dict[str, t.Any] | None = None, + filters: list[str] | None = None, ) -> data_models.CapellaWorkItem: """Add a new custom field tree diagram.""" assert converter_data.work_item, "No work item set yet" diagram = converter_data.capella_element.tree_view + for filter in filters or []: + diagram.filters.add(filter) self._draw_additional_attributes_diagram( converter_data.work_item, diff --git a/tests/data/model_elements/config.yaml b/tests/data/model_elements/config.yaml index eaa72952..fbae34a6 100644 --- a/tests/data/model_elements/config.yaml +++ b/tests/data/model_elements/config.yaml @@ -61,6 +61,10 @@ sa: capella_attr: outputs.exchanges include: Exchange Items: exchange_items + serializer: + add_context_diagram: + filters: + - EX_ITEMS_OR_EXCH # functional exchange or exchange item name FunctionalExchange: links: - exchanged_items diff --git a/tests/test_elements.py b/tests/test_elements.py index 602fbd1f..0975dccd 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -8,11 +8,11 @@ from unittest import mock import capellambse -import capellambse_context_diagrams.context import markupsafe import polarion_rest_api_client as polarion_api import pytest from capellambse.model import common +from capellambse_context_diagrams import context, filters from capella2polarion import data_models from capella2polarion.connectors import polarion_repo @@ -1717,6 +1717,75 @@ def test_add_context_diagram(model: capellambse.MelodyModel): "__C2P__context_diagram.svg", ) + @staticmethod + @pytest.mark.parametrize( + "context_diagram_filter", + [ + "SHOW_EX_ITEMS", + "EX_ITEMS", + "EX_ITEMS_OR_EXCH", + "NO_UUID", + "SYSTEM_EX_RELABEL", + ], + ) + def test_add_context_diagram_with_params( + model: capellambse.MelodyModel, + monkeypatch: pytest.MonkeyPatch, + context_diagram_filter: str, + ): + uuid = "00e7b925-cf4c-4cb0-929e-5409a1cd872b" + fnc = model.by_uuid(uuid) + config = {"add_context_diagram": {"filters": [context_diagram_filter]}} + type_config = converter_config.CapellaTypeConfig( + "systemFunction", config, [] + ) + expected_filter = getattr(filters, context_diagram_filter) + monkeypatch.setattr( + element_converter.CapellaWorkItemSerializer, + "_draw_additional_attributes_diagram", + draw_diagram_mock := mock.MagicMock(), + ) + serializer = element_converter.CapellaWorkItemSerializer( + model, + polarion_repo.PolarionDataRepository(), + {uuid: data_session.ConverterData("sa", type_config, fnc)}, + True, + ) + + work_item = serializer.serialize(uuid) + + assert draw_diagram_mock.call_count == 1 + assert (inputs := draw_diagram_mock.call_args[0])[0] == work_item + assert expected_filter in inputs[1].filters + + @staticmethod + def test_add_tree_view_with_params( + model: capellambse.MelodyModel, + ): + cls = model.by_uuid("c710f1c2-ede6-444e-9e2b-0ff30d7fd040") + config = {"add_tree_diagram": {"render_params": {"depth": 1}}} + type_config = converter_config.CapellaTypeConfig( + "systemFunction", config, [] + ) + serializer = element_converter.CapellaWorkItemSerializer( + model, + polarion_repo.PolarionDataRepository(), + { + TEST_OCAP_UUID: data_session.ConverterData( + "pa", type_config, cls + ) + }, + True, + ) + + with mock.patch.object( + context.ContextDiagram, "render" + ) as wrapped_render: + serializer.serialize_all() + + assert wrapped_render.call_count == 1 + assert wrapped_render.call_args_list[0][1] == {"depth": 1} + def test_add_jinja_to_description(self, model: capellambse.MelodyModel): uuid = "c710f1c2-ede6-444e-9e2b-0ff30d7fd040" type_config = converter_config.CapellaTypeConfig( @@ -1852,7 +1921,28 @@ def test_generic_work_item_with_type_prefix( assert work_item == data_models.CapellaWorkItem(**expected) @staticmethod - def test_read_config_with_custom_params(model: capellambse.MelodyModel): + def test_read_config_context_diagram_with_params(): + expected_filter = ( + "capellambse_context_diagrams-show.exchanges.or.exchange.items." + "filter" + ) + config = converter_config.ConverterConfig() + with open(TEST_MODEL_ELEMENTS_CONFIG, "r", encoding="utf8") as f: + config.read_config_file(f) + + type_config = config.get_type_config("sa", "SystemFunction") + + assert type_config is not None + assert isinstance(type_config.converters, dict) + assert "add_context_diagram" in type_config.converters + assert type_config.converters["add_context_diagram"]["filters"] == [ + expected_filter + ] + + @staticmethod + def test_read_config_tree_view_with_params( + model: capellambse.MelodyModel, + ): cap = model.by_uuid("c710f1c2-ede6-444e-9e2b-0ff30d7fd040") config = converter_config.ConverterConfig() with open(TEST_MODEL_ELEMENTS_CONFIG, "r", encoding="utf8") as f: @@ -1878,9 +1968,10 @@ def test_read_config_with_custom_params(model: capellambse.MelodyModel): ) with mock.patch.object( - capellambse_context_diagrams.context.ContextDiagram, "render" + context.ContextDiagram, "render" ) as wrapped_render: serializer.serialize_all() + assert wrapped_render.call_count == 1 assert wrapped_render.call_args_list[0][1] == {"depth": 1}