From ac5102c74026b4a793108f94a561cbf6bb5e27d4 Mon Sep 17 00:00:00 2001 From: Michael Harbarth Date: Tue, 27 Feb 2024 10:58:22 +0100 Subject: [PATCH 01/18] feat: add realization view --- .../converters/element_converter.py | 55 ++++++------------- tests/test_elements.py | 1 - 2 files changed, 17 insertions(+), 39 deletions(-) diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index 237e8f7..f507bcf 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -1,6 +1,7 @@ # Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """Objects for serialization of capella objects to workitems.""" + from __future__ import annotations import collections @@ -25,9 +26,7 @@ from capella2polarion.connectors import polarion_repo from capella2polarion.converters import data_session, polarion_html_helper -RE_DESCR_LINK_PATTERN = re.compile( - r"([^<]+)<\/a>" -) +RE_DESCR_LINK_PATTERN = re.compile(r"([^<]+)<\/a>") RE_CAMEL_CASE_2ND_WORD_PATTERN = re.compile(r"([a-z]+)([A-Z][a-z]+)") logger = logging.getLogger(__name__) @@ -40,9 +39,7 @@ def resolve_element_type(type_: str) -> str: return type_[0].lower() + type_[1:] -def _format_texts( - type_texts: dict[str, list[str]] -) -> dict[str, dict[str, str]]: +def _format_texts(type_texts: dict[str, list[str]]) -> dict[str, dict[str, str]]: def _format(texts: list[str]) -> dict[str, str]: if len(texts) > 1: items = "".join(f"
  • {text}
  • " for text in texts) @@ -85,9 +82,7 @@ def serialize(self, uuid: str) -> data_model.CapellaWorkItem | None: """Return a CapellaWorkItem for the given diagram or element.""" converter_data = self.converter_session[uuid] work_item_id = None - if old := self.capella_polarion_mapping.get_work_item_by_capella_uuid( - uuid - ): + if old := self.capella_polarion_mapping.get_work_item_by_capella_uuid(uuid): work_item_id = old.id self.__generic_work_item(converter_data, work_item_id) @@ -102,9 +97,7 @@ def serialize(self, uuid: str) -> data_model.CapellaWorkItem | None: ] = getattr(self, f"_{converter}") serializer(converter_data, **params) except Exception as error: - converter_data.errors.add( - ", ".join([str(a) for a in error.args]) - ) + converter_data.errors.add(", ".join([str(a) for a in error.args])) converter_data.work_item = None if converter_data.errors: @@ -160,9 +153,7 @@ def _draw_diagram_svg( attachment = None return ( - polarion_html_helper.generate_image_html( - title, file_name, max_width, cls - ), + polarion_html_helper.generate_image_html(title, file_name, max_width, cls), attachment, ) @@ -179,9 +170,7 @@ def _render_jinja_template( model=self.model, work_item=converter_data.work_item, ) - _, text, _ = self._sanitize_text( - converter_data.capella_element, rendered_jinja - ) + _, text, _ = self._sanitize_text(converter_data.capella_element, rendered_jinja) return text def setup_env(self, env: jinja2.Environment): @@ -255,7 +244,9 @@ def _draw_additional_attributes_diagram( "value": diagram_html, } - def _sanitize_linked_text(self, obj: m.ModelElement | m.Diagram) -> tuple[ + def _sanitize_linked_text( + self, obj: m.ModelElement | m.Diagram + ) -> tuple[ list[str], markupsafe.Markup, list[data_model.Capella2PolarionAttachment], @@ -281,9 +272,7 @@ def _sanitize_text( ]: referenced_uuids: list[str] = [] replaced_markup = RE_DESCR_LINK_PATTERN.sub( - lambda match: self._replace_markup( - obj.uuid, match, referenced_uuids, 2 - ), + lambda match: self._replace_markup(obj.uuid, match, referenced_uuids, 2), text, ) @@ -302,9 +291,7 @@ def repair_images(node: etree._Element) -> None: file_path = pathlib.PurePosixPath(*file_url.parts[1:]) mime_type, _ = mimetypes.guess_type(file_url) resources = self.model.resources - filehandler = resources[ - ["\x00", workspace][workspace in resources] - ] + filehandler = resources[["\x00", workspace][workspace in resources]] try: with filehandler.open(file_path, "r") as img: content = img.read() @@ -355,9 +342,7 @@ def _replace_markup( self.converter_session[origin_uuid].errors.add( f"Non-existing model element referenced in description: {uuid}" ) - return polarion_html_helper.strike_through( - match.group(default_group) - ) + return polarion_html_helper.strike_through(match.group(default_group)) if pid := self.capella_polarion_mapping.get_work_item_id(uuid): referenced_uuids.append(uuid) return polarion_html_helper.POLARION_WORK_ITEM_URL.format(pid=pid) @@ -379,9 +364,7 @@ def _get_requirement_types_text( continue if not (req.type and req.text): - identifier = ( - req.long_name or req.name or req.summary or req.uuid - ) + identifier = req.long_name or req.name or req.summary or req.uuid self.converter_session[obj.uuid].errors.add( f"Found Requirement without text or type on {identifier!r}" ) @@ -467,9 +450,7 @@ def get_condition(cap: m.ModelElement, name: str) -> str: post_condition = get_condition(obj, "postcondition") assert converter_data.work_item, "No work item set yet" - converter_data.work_item.preCondition = polarion_api.HtmlContent( - pre_condition - ) + converter_data.work_item.preCondition = polarion_api.HtmlContent(pre_condition) converter_data.work_item.postCondition = polarion_api.HtmlContent( post_condition ) @@ -568,9 +549,7 @@ def _jinja_as_description( assert ( converter_data.work_item.description ), "Description should already be defined" - converter_data.work_item.description.value = ( - self._render_jinja_template( - template_folder, template_path, converter_data - ) + converter_data.work_item.description.value = self._render_jinja_template( + template_folder, template_path, converter_data ) return converter_data.work_item diff --git a/tests/test_elements.py b/tests/test_elements.py index ea9e294..72f8ca8 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -2124,7 +2124,6 @@ def test_read_config_tree_view_with_params( with mock.patch.object( context.ContextDiagram, "render" ) as wrapped_render: - wis = serializer.serialize_all() _ = wis[0].attachments[0].content_bytes From ffa2d3fb6283c30914df0b91cc91ff008805e167 Mon Sep 17 00:00:00 2001 From: Michael Harbarth Date: Tue, 27 Feb 2024 15:08:24 +0100 Subject: [PATCH 02/18] fix: support None typed serialization configuration instead of dict type only --- .../converters/converter_config.py | 7 +- .../converters/element_converter.py | 99 +++++++++---------- 2 files changed, 52 insertions(+), 54 deletions(-) diff --git a/capella2polarion/converters/converter_config.py b/capella2polarion/converters/converter_config.py index 5d5aff1..aa64c3e 100644 --- a/capella2polarion/converters/converter_config.py +++ b/capella2polarion/converters/converter_config.py @@ -1,6 +1,7 @@ # Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """Module providing capella2polarion config class.""" + from __future__ import annotations import dataclasses @@ -283,7 +284,7 @@ def config_matches(config: CapellaTypeConfig | None, **kwargs: t.Any) -> bool: def _read_capella_type_configs( - conf: dict[str, t.Any] | list[dict[str, t.Any]] | None + conf: dict[str, t.Any] | list[dict[str, t.Any]] | None, ) -> list[dict]: if conf is None: return [{}] @@ -300,7 +301,7 @@ def _read_capella_type_configs( def _force_dict( - config: str | list[str] | dict[str, dict[str, t.Any]] | None + config: str | list[str] | dict[str, dict[str, t.Any]] | None, ) -> dict[str, dict[str, t.Any]]: match config: case None: @@ -323,7 +324,7 @@ def add_prefix(polarion_type: str, prefix: str) -> str: def _filter_converter_config( - config: dict[str, dict[str, t.Any]] + config: dict[str, dict[str, t.Any]], ) -> dict[str, dict[str, t.Any]]: custom_converters = ( "include_pre_and_post_condition", diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index f507bcf..9b73208 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -373,6 +373,30 @@ def _get_requirement_types_text( type_texts[req.type.long_name].append(req.text) return _format_texts(type_texts) + def _add_diagram( + self, + converter_data: data_session.ConverterData, + diagram_attr: str, + diagram_label: str, + render_params: dict[str, t.Any] | None = None, + filters: list[str] | None = None, + ) -> data_model.CapellaWorkItem: + """Add a new custom field diagram based on provided attributes.""" + assert converter_data.work_item, "No work item set yet" + diagram = getattr(converter_data.capella_element, diagram_attr) + + for filter in filters or []: + diagram.filters.add(filter) + + self._draw_additional_attributes_diagram( + converter_data.work_item, + diagram, + diagram_attr, + diagram_label, + render_params, + ) + return converter_data.work_item + # Serializer implementation starts below def __generic_work_item( @@ -481,75 +505,48 @@ def _add_context_diagram( render_params: dict[str, t.Any] | None = None, filters: list[str] | None = None, ) -> data_model.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, - diagram, + return self._add_diagram( + converter_data, "context_diagram", "Context Diagram", render_params, + filters, ) - return converter_data.work_item - def _add_tree_diagram( self, converter_data: data_session.ConverterData, render_params: dict[str, t.Any] | None = None, filters: list[str] | None = None, ) -> data_model.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, - diagram, - "tree_view", - "Tree View", - render_params, + return self._add_diagram( + converter_data, "tree_view", "Tree View", render_params, filters ) - return converter_data.work_item - - def _add_jinja_fields( + def _add_realization_diagram( self, converter_data: data_session.ConverterData, - fields: dict[str, dict[str, str]], + render_params: dict[str, t.Any] | None = None, + filters: list[str] | None = None, ) -> data_model.CapellaWorkItem: - """Add a new custom field and fill it with rendered jinja content.""" - assert converter_data.work_item, "No work item set yet" - for field, jinja_properties in fields.items(): - converter_data.work_item.additional_attributes[field] = { - "type": "text/html", - "value": self._render_jinja_template( - jinja_properties.get("template_folder", ""), - jinja_properties["template_path"], - converter_data, - ), - } - - return converter_data.work_item + return self._add_diagram( + converter_data, + "realization_view", + "Realization Diagram", + render_params, + filters, + ) - def _jinja_as_description( + def _add_cable_tree_diagram( self, converter_data: data_session.ConverterData, - template_path: str, - template_folder: str = "", + render_params: dict[str, t.Any] | None = None, + filters: list[str] | None = None, ) -> data_model.CapellaWorkItem: - """Use a Jinja template to render the description content.""" - assert converter_data.work_item, "No work item set yet" - assert ( - converter_data.work_item.description - ), "Description should already be defined" - converter_data.work_item.description.value = self._render_jinja_template( - template_folder, template_path, converter_data + return self._add_diagram( + converter_data, + "cable_tree", + "Cable Tree Diagram", + render_params, + filters, ) - return converter_data.work_item From bce5d00e0ce01ed85ce44d5d5622a9172c034333 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Wed, 20 Nov 2024 16:11:29 +0100 Subject: [PATCH 03/18] ci: Black formatting --- .../converters/element_converter.py | 37 +++++++++++++++++++ tests/test_elements.py | 9 +++-- 2 files changed, 42 insertions(+), 4 deletions(-) diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index 9b73208..f315baa 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -550,3 +550,40 @@ def _add_cable_tree_diagram( render_params, filters, ) + + def _add_jinja_fields( + self, + converter_data: data_session.ConverterData, + fields: dict[str, dict[str, str]], + ) -> data_model.CapellaWorkItem: + """Add a new custom field and fill it with rendered jinja content.""" + assert converter_data.work_item, "No work item set yet" + for field, jinja_properties in fields.items(): + converter_data.work_item.additional_attributes[field] = { + "type": "text/html", + "value": self._render_jinja_template( + jinja_properties.get("template_folder", ""), + jinja_properties["template_path"], + converter_data, + ), + } + + return converter_data.work_item + + def _jinja_as_description( + self, + converter_data: data_session.ConverterData, + template_path: str, + template_folder: str = "", + ) -> data_model.CapellaWorkItem: + """Use a Jinja template to render the description content.""" + assert converter_data.work_item, "No work item set yet" + assert ( + converter_data.work_item.description + ), "Description should already be defined" + converter_data.work_item.description.value = ( + self._render_jinja_template( + template_folder, template_path, converter_data + ) + ) + return converter_data.work_item diff --git a/tests/test_elements.py b/tests/test_elements.py index 72f8ca8..5125dea 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -894,16 +894,17 @@ def test_create_new_work_item(base_object: BaseObjectContainer): base_object.pw.project_client.work_items.get_all = ( polarion_api_get_all_work_items ) + polarion_api_create_work_items = mock.MagicMock() + polarion_api_create_work_items.side_effect = _set_work_item_id + base_object.pw.project_client.work_items.create = ( + polarion_api_create_work_items + ) base_object.pw.load_polarion_work_item_map() base_object.pw.create_missing_work_items( base_object.mc.converter_session ) - polarion_api_create_work_items = ( - base_object.pw.project_client.work_items.create - ) - assert polarion_api_create_work_items.call_count == 1 assert len(polarion_api_create_work_items.call_args[0][0]) == 1 work_item = polarion_api_create_work_items.call_args[0][0][0] From 97fbdd104e577d1b97c1d6ecc0c0374ccf5fc259 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Thu, 21 Nov 2024 11:37:48 +0100 Subject: [PATCH 04/18] fix: Add new serializers to custom converters --- capella2polarion/converters/converter_config.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/capella2polarion/converters/converter_config.py b/capella2polarion/converters/converter_config.py index aa64c3e..bcf40b4 100644 --- a/capella2polarion/converters/converter_config.py +++ b/capella2polarion/converters/converter_config.py @@ -331,6 +331,8 @@ def _filter_converter_config( "linked_text_as_description", "add_context_diagram", "add_tree_diagram", + "add_realization_diagram", + "add_cable_tree_diagram", "add_jinja_fields", "jinja_as_description", ) From e876c3b7cd35f3df6816860820aec613926df955 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Thu, 21 Nov 2024 11:38:04 +0100 Subject: [PATCH 05/18] chore: Black formatting --- capella2polarion/__main__.py | 1 + .../converters/element_converter.py | 48 +++++++++++++------ .../converters/text_work_item_provider.py | 1 + 3 files changed, 36 insertions(+), 14 deletions(-) diff --git a/capella2polarion/__main__.py b/capella2polarion/__main__.py index a0fd610..c05710d 100644 --- a/capella2polarion/__main__.py +++ b/capella2polarion/__main__.py @@ -1,6 +1,7 @@ # Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """Main entry point into capella2polarion.""" + from __future__ import annotations import logging diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index f315baa..4e493ab 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -26,7 +26,9 @@ from capella2polarion.connectors import polarion_repo from capella2polarion.converters import data_session, polarion_html_helper -RE_DESCR_LINK_PATTERN = re.compile(r"
    ([^<]+)<\/a>") +RE_DESCR_LINK_PATTERN = re.compile( + r"([^<]+)<\/a>" +) RE_CAMEL_CASE_2ND_WORD_PATTERN = re.compile(r"([a-z]+)([A-Z][a-z]+)") logger = logging.getLogger(__name__) @@ -39,7 +41,9 @@ def resolve_element_type(type_: str) -> str: return type_[0].lower() + type_[1:] -def _format_texts(type_texts: dict[str, list[str]]) -> dict[str, dict[str, str]]: +def _format_texts( + type_texts: dict[str, list[str]] +) -> dict[str, dict[str, str]]: def _format(texts: list[str]) -> dict[str, str]: if len(texts) > 1: items = "".join(f"
  • {text}
  • " for text in texts) @@ -82,7 +86,9 @@ def serialize(self, uuid: str) -> data_model.CapellaWorkItem | None: """Return a CapellaWorkItem for the given diagram or element.""" converter_data = self.converter_session[uuid] work_item_id = None - if old := self.capella_polarion_mapping.get_work_item_by_capella_uuid(uuid): + if old := self.capella_polarion_mapping.get_work_item_by_capella_uuid( + uuid + ): work_item_id = old.id self.__generic_work_item(converter_data, work_item_id) @@ -97,7 +103,9 @@ def serialize(self, uuid: str) -> data_model.CapellaWorkItem | None: ] = getattr(self, f"_{converter}") serializer(converter_data, **params) except Exception as error: - converter_data.errors.add(", ".join([str(a) for a in error.args])) + converter_data.errors.add( + ", ".join([str(a) for a in error.args]) + ) converter_data.work_item = None if converter_data.errors: @@ -153,7 +161,9 @@ def _draw_diagram_svg( attachment = None return ( - polarion_html_helper.generate_image_html(title, file_name, max_width, cls), + polarion_html_helper.generate_image_html( + title, file_name, max_width, cls + ), attachment, ) @@ -170,7 +180,9 @@ def _render_jinja_template( model=self.model, work_item=converter_data.work_item, ) - _, text, _ = self._sanitize_text(converter_data.capella_element, rendered_jinja) + _, text, _ = self._sanitize_text( + converter_data.capella_element, rendered_jinja + ) return text def setup_env(self, env: jinja2.Environment): @@ -244,9 +256,7 @@ def _draw_additional_attributes_diagram( "value": diagram_html, } - def _sanitize_linked_text( - self, obj: m.ModelElement | m.Diagram - ) -> tuple[ + def _sanitize_linked_text(self, obj: m.ModelElement | m.Diagram) -> tuple[ list[str], markupsafe.Markup, list[data_model.Capella2PolarionAttachment], @@ -272,7 +282,9 @@ def _sanitize_text( ]: referenced_uuids: list[str] = [] replaced_markup = RE_DESCR_LINK_PATTERN.sub( - lambda match: self._replace_markup(obj.uuid, match, referenced_uuids, 2), + lambda match: self._replace_markup( + obj.uuid, match, referenced_uuids, 2 + ), text, ) @@ -291,7 +303,9 @@ def repair_images(node: etree._Element) -> None: file_path = pathlib.PurePosixPath(*file_url.parts[1:]) mime_type, _ = mimetypes.guess_type(file_url) resources = self.model.resources - filehandler = resources[["\x00", workspace][workspace in resources]] + filehandler = resources[ + ["\x00", workspace][workspace in resources] + ] try: with filehandler.open(file_path, "r") as img: content = img.read() @@ -342,7 +356,9 @@ def _replace_markup( self.converter_session[origin_uuid].errors.add( f"Non-existing model element referenced in description: {uuid}" ) - return polarion_html_helper.strike_through(match.group(default_group)) + return polarion_html_helper.strike_through( + match.group(default_group) + ) if pid := self.capella_polarion_mapping.get_work_item_id(uuid): referenced_uuids.append(uuid) return polarion_html_helper.POLARION_WORK_ITEM_URL.format(pid=pid) @@ -364,7 +380,9 @@ def _get_requirement_types_text( continue if not (req.type and req.text): - identifier = req.long_name or req.name or req.summary or req.uuid + identifier = ( + req.long_name or req.name or req.summary or req.uuid + ) self.converter_session[obj.uuid].errors.add( f"Found Requirement without text or type on {identifier!r}" ) @@ -474,7 +492,9 @@ def get_condition(cap: m.ModelElement, name: str) -> str: post_condition = get_condition(obj, "postcondition") assert converter_data.work_item, "No work item set yet" - converter_data.work_item.preCondition = polarion_api.HtmlContent(pre_condition) + converter_data.work_item.preCondition = polarion_api.HtmlContent( + pre_condition + ) converter_data.work_item.postCondition = polarion_api.HtmlContent( post_condition ) diff --git a/capella2polarion/converters/text_work_item_provider.py b/capella2polarion/converters/text_work_item_provider.py index a075102..282f6c3 100644 --- a/capella2polarion/converters/text_work_item_provider.py +++ b/capella2polarion/converters/text_work_item_provider.py @@ -1,6 +1,7 @@ # Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """Provides a class to generate and inset text work items in documents.""" + import polarion_rest_api_client as polarion_api from lxml import html From f0e9bdd35068be285ef458dbf0a845c3561f74f5 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Thu, 21 Nov 2024 11:38:29 +0100 Subject: [PATCH 06/18] test: Add testcases for new serializers --- tests/data/model/Melody Model Test.capella | 9 +++- tests/test_elements.py | 56 +++++++++++++++++----- 2 files changed, 53 insertions(+), 12 deletions(-) diff --git a/tests/data/model/Melody Model Test.capella b/tests/data/model/Melody Model Test.capella index 7ea8f5e..ddf2137 100644 --- a/tests/data/model/Melody Model Test.capella +++ b/tests/data/model/Melody Model Test.capella @@ -2058,7 +2058,11 @@ The predator is far away + human="true"> + + id="74bd0ab3-6a28-4025-822e-90201445a56e" targetElement="#3612f112-f0c7-42ec-b0e9-f53afc1ef486" sourceElement="#b4e39757-b0fd-41ff-a7b8-c9fc36de2ca9"/> + diff --git a/tests/test_elements.py b/tests/test_elements.py index 5125dea..86b5cc1 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -1913,22 +1913,56 @@ def test_add_context_diagram_with_params( assert expected_filter in inputs[1].filters @staticmethod - def test_add_tree_view_with_params( + @pytest.mark.parametrize( + "uuid, converter, type_name, render_params, layer", + [ + pytest.param( + "c710f1c2-ede6-444e-9e2b-0ff30d7fd040", + "add_tree_diagram", + "systemFunction", + {"depth": 1}, + "pa", + id="add_tree_diagram", + ), + pytest.param( + "344a405e-c7e5-4367-8a9a-41d3d9a27f81", + "add_realization_diagram", + "systemComponent", + {"depth": 1, "search_direction": "ALL"}, + "sa", + id="add_realization_diagram", + ), + pytest.param( + "3078ec08-956a-4c61-87ed-0143d1d66715", + "add_cable_tree_diagram", + "physicalLink", + { + "display_port_labels": True, + "port_label_position": "OUTSIDE", + }, + "pa", + id="add_cable_tree_diagram", + ), + ], + ) + def test_context_diagram_serializer( + uuid: str, + converter: str, + type_name: str, + render_params: dict[str, t.Any], + layer: str, 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, [] + config = {converter: {"render_params": render_params}} + type_config = data_session.ConverterData( + layer, + converter_config.CapellaTypeConfig(type_name, config, []), + model.by_uuid(uuid), ) serializer = element_converter.CapellaWorkItemSerializer( model, polarion_repo.PolarionDataRepository(), - { - TEST_OCAP_UUID: data_session.ConverterData( - "pa", type_config, cls - ) - }, + {uuid: type_config}, True, ) @@ -1939,7 +1973,7 @@ def test_add_tree_view_with_params( _ = wis[0].attachments[0].content_bytes assert wrapped_render.call_count == 1 - assert wrapped_render.call_args_list[0][1] == {"depth": 1} + assert wrapped_render.call_args_list[0][1] == render_params def test_add_jinja_to_description(self, model: capellambse.MelodyModel): uuid = "c710f1c2-ede6-444e-9e2b-0ff30d7fd040" From f0a64b63adb20725ce530e82da64a3739641af32 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Thu, 21 Nov 2024 11:38:40 +0100 Subject: [PATCH 07/18] docs: Document new serializers --- docs/source/features/sync.rst | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/docs/source/features/sync.rst b/docs/source/features/sync.rst index 1c2c247..35245f0 100644 --- a/docs/source/features/sync.rst +++ b/docs/source/features/sync.rst @@ -71,7 +71,7 @@ specific serializer alone: | | will be passed to the render function of capellambse.| | | See `context-diagrams filters`_ for documentation. | +--------------------------------------+------------------------------------------------------+ -| add_tree_view | A serializer adding a tree view diagram to the | +| add_tree_diagram | A serializer adding a tree view diagram to the | | | work item. Same requirements as for | | | ``add_context_diagram``. `Tree View Documentation`_. | | | You can provide ``render_params`` in the config and | @@ -79,6 +79,26 @@ specific serializer alone: | | capellambse. | | | ``filters`` are available here too. | +--------------------------------------+------------------------------------------------------+ +| add_realization_diagram | A serializer adding a realization diagram to the | +| | work item. Requires similar setup as | +| | ``add_context_diagram``. `Realization Diagram | +| | Documentation`_. | +| | You can provide ``render_params`` in the config and | +| | these will be passed to the render function of | +| | capellambse. | +| | ``filters`` can also be provided for additional | +| | customization. | ++--------------------------------------+------------------------------------------------------+ +| add_cable_tree_diagram | A serializer adding a cable tree diagram to the | +| | work item. Requires similar setup as | +| | ``add_context_diagram``. `Cable Tree Diagram | +| | Documentation`_. | +| | You can provide ``render_params`` in the config and | +| | these will be passed to the render function of | +| | capellambse. | +| | ``filters`` are also supported here for additional | +| | customization. | ++--------------------------------------+------------------------------------------------------+ | add_jinja_fields | A serializer that allows custom field values to be | | | filled with rendered Jinja2 template content. This | | | makes it possible to add complex HTML structures | @@ -93,6 +113,8 @@ specific serializer alone: .. _context-diagrams documentation: https://dsd-dbs.github.io/capellambse-context-diagrams/#context-diagram-extension-for-capellambse .. _Tree View documentation: https://dsd-dbs.github.io/capellambse-context-diagrams/tree_view/ +.. _Realization Diagram documentation: https://dsd-dbs.github.io/capellambse-context-diagrams/realization_view/ +.. _Cable Tree Diagram documentation: https://dsd-dbs.github.io/capellambse-context-diagrams/cable_tree/ .. _context-diagrams filters: https://dsd-dbs.github.io/capellambse-context-diagrams/extras/filters/ Links From e998619fc40c344b86626d79c48f606de0f2d705 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Fri, 22 Nov 2024 09:42:14 +0100 Subject: [PATCH 08/18] test: Fix broken test --- tests/test_elements.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/tests/test_elements.py b/tests/test_elements.py index 86b5cc1..3317c9b 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -894,17 +894,16 @@ def test_create_new_work_item(base_object: BaseObjectContainer): base_object.pw.project_client.work_items.get_all = ( polarion_api_get_all_work_items ) - polarion_api_create_work_items = mock.MagicMock() - polarion_api_create_work_items.side_effect = _set_work_item_id - base_object.pw.project_client.work_items.create = ( - polarion_api_create_work_items - ) base_object.pw.load_polarion_work_item_map() base_object.pw.create_missing_work_items( base_object.mc.converter_session ) + polarion_api_create_work_items = ( + base_object.pw.project_client.work_items.create + ) + assert polarion_api_create_work_items.call_count == 1 assert len(polarion_api_create_work_items.call_args[0][0]) == 1 work_item = polarion_api_create_work_items.call_args[0][0][0] From 5a71960e767b85140b7a897d1905bad3458142a6 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Mon, 2 Dec 2024 14:51:03 +0100 Subject: [PATCH 09/18] test: Change context diagram checksum --- tests/test_workitem_attachments.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_workitem_attachments.py b/tests/test_workitem_attachments.py index e568df0..d38bbc3 100644 --- a/tests/test_workitem_attachments.py +++ b/tests/test_workitem_attachments.py @@ -30,7 +30,7 @@ "0ed1417e8e4717524bc91162dcf8633afca686e93f8b036d0bc48d81f0444f56" ) CONTEXT_DIAGRAM_CHECKSUM = ( - "2b86192f2f65353512e1b4af0e652577d0ca3d0cf8595f5dcfba7d52bcb6d702" + "572cb7ba53bcde56638a119fafc1304af294467d8c851f4b2cc35ce2f5d231eb" ) TEST_DIAG_UUID = "_APOQ0QPhEeynfbzU12yy7w" From 45d314f3be39372ac27b95ced3afcef9b60e0f42 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Mon, 2 Dec 2024 14:52:06 +0100 Subject: [PATCH 10/18] refactor: Move assertions into serialization This removes unncessary iteration over all `work_items`. --- capella2polarion/converters/element_converter.py | 4 ++++ capella2polarion/converters/model_converter.py | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index 4e493ab..7db2ebf 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -108,6 +108,10 @@ def serialize(self, uuid: str) -> data_model.CapellaWorkItem | None: ) converter_data.work_item = None + if converter_data.work_item is not None: + assert converter_data.work_item.title is not None + assert converter_data.work_item.type is not None + if converter_data.errors: log_args = ( converter_data.capella_element._short_repr_(), diff --git a/capella2polarion/converters/model_converter.py b/capella2polarion/converters/model_converter.py index 13edbf6..959f6a2 100644 --- a/capella2polarion/converters/model_converter.py +++ b/capella2polarion/converters/model_converter.py @@ -112,10 +112,6 @@ def generate_work_items( generate_attachments, ) work_items = serializer.serialize_all() - for work_item in work_items: - assert work_item.title is not None - assert work_item.type is not None - if generate_links: self.generate_work_item_links( polarion_data_repo, generate_grouped_links_custom_fields From d47b69c48fd0fcfbf4bba7eba073f721a011ade0 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Mon, 2 Dec 2024 15:23:45 +0100 Subject: [PATCH 11/18] test: Add tests for all context diagram serializers --- tests/test_elements.py | 451 +++++++++-------------------- tests/test_workitem_attachments.py | 163 ++++++----- 2 files changed, 229 insertions(+), 385 deletions(-) diff --git a/tests/test_elements.py b/tests/test_elements.py index 3317c9b..49de5d0 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -54,7 +54,10 @@ TEST_CAP_REAL = "b80b3141-a7fc-48c7-84b2-1467dcef5fce" TEST_CONSTRAINT = "95cbd4af-7224-43fe-98cb-f13dda540b8e" TEST_SYS_FNC = "ceffa011-7b66-4b3c-9885-8e075e312ffa" +TEST_SYS_FNC_CTX = "c710f1c2-ede6-444e-9e2b-0ff30d7fd040" TEST_SYS_FNC_EX = "1a414995-f4cd-488c-8152-486e459fb9de" +TEST_SYS_CMP = "344a405e-c7e5-4367-8a9a-41d3d9a27f81" +TEST_PHYS_LINK = "3078ec08-956a-4c61-87ed-0143d1d66715" TEST_DIAG_DESCR = ( ' GroupedLinksBaseObject: - config = converter_config.CapellaTypeConfig( - "fakeModelObject", links=[LINK_CONFIG] - ) + config = converter_config.CapellaTypeConfig("fakeModelObject", links=[LINK_CONFIG]) mock_model = mock.MagicMock() fake_2 = FakeModelObject("uuid2", "Fake 2") fake_1 = FakeModelObject("uuid1", "Fake 1") @@ -218,8 +219,8 @@ def diagr_base_object( ) } - base_object.pw.polarion_data_repo = ( - polarion_repo.PolarionDataRepository([work_item]) + base_object.pw.polarion_data_repo = polarion_repo.PolarionDataRepository( + [work_item] ) return base_object @@ -254,10 +255,7 @@ def test_delete_diagrams(diagr_base_object: BaseObjectContainer): pw.delete_orphaned_work_items(diagr_base_object.mc.converter_session) assert pw.project_client is not None assert pw.project_client.work_items.delete.call_count == 1 - assert ( - pw.project_client.work_items.delete.call_args[0][0][0].id - == "Diag-1" - ) + assert pw.project_client.work_items.delete.call_args[0][0][0].id == "Diag-1" assert pw.project_client.work_items.create.call_count == 0 @@ -313,9 +311,7 @@ def test_create_work_items_with_special_polarion_type( base_object.mc.converter_session = { uuid: data_session.ConverterData( "oa", - converter_config.CapellaTypeConfig( - _type[0].lower() + _type[1:] - ), + converter_config.CapellaTypeConfig(_type[0].lower() + _type[1:]), model.by_uuid(uuid), ) } @@ -353,9 +349,7 @@ def test_create_links_custom_resolver(base_object: BaseObjectContainer): polarion_role="description_reference", ) ] - base_object.mc.converter_session["uuid2"].description_references = [ - "uuid1" - ] + base_object.mc.converter_session["uuid2"].description_references = ["uuid1"] expected = polarion_api.WorkItemLink( "Obj-2", "Obj-1", @@ -404,15 +398,13 @@ def test_create_links_custom_exchanges_resolver( link_config = converter_config.LinkConfig( capella_attr="inputs.exchanges", polarion_role="input_exchanges" ) - base_object.mc.converter_session[function_uuid] = ( - data_session.ConverterData( - "fa", - converter_config.CapellaTypeConfig( - type(funtion_obj).__name__, links=[link_config] - ), - funtion_obj, - work_item_obj_1, - ) + base_object.mc.converter_session[function_uuid] = data_session.ConverterData( + "fa", + converter_config.CapellaTypeConfig( + type(funtion_obj).__name__, links=[link_config] + ), + funtion_obj, + work_item_obj_1, ) base_object.mc.converter_session[uuid] = data_session.ConverterData( "fa", @@ -449,9 +441,7 @@ def test_create_links_logs_error_when_no_uuid_is_found_on_value( ) no_uuid = FakeModelObject("") del no_uuid.uuid - base_object.mc.converter_session["uuid1"].capella_element.attribute = ( - no_uuid - ) + base_object.mc.converter_session["uuid1"].capella_element.attribute = no_uuid with caplog.at_level(logging.ERROR): link_serializer = link_converter.LinkSerializer( @@ -577,9 +567,7 @@ def test_create_links_with_new_links_and_errors( polarion_role="invalid_role", ), ] - base_object.mc.converter_session["uuid2"].description_references = [ - "uuid1" - ] + base_object.mc.converter_session["uuid2"].description_references = ["uuid1"] base_object.mc.converter_session["uuid2"].errors = set() expected_link = polarion_api.WorkItemLink( @@ -748,9 +736,7 @@ def test_update_work_items( uuid_capella="uuid1", status="open", title="Something", - description=polarion_api.HtmlContent( - markupsafe.Markup("Test") - ), + description=polarion_api.HtmlContent(markupsafe.Markup("Test")), ) ] polarion_api_get_all_work_items = mock.MagicMock() @@ -763,14 +749,14 @@ def test_update_work_items( base_object.pw.load_polarion_work_item_map() - base_object.mc.converter_session["uuid1"].work_item = ( - data_model.CapellaWorkItem( - id="Obj-1", - uuid_capella="uuid1", - title="Fake 1", - type="type", - description=polarion_api.HtmlContent(markupsafe.Markup("")), - ) + base_object.mc.converter_session[ + "uuid1" + ].work_item = data_model.CapellaWorkItem( + id="Obj-1", + uuid_capella="uuid1", + title="Fake 1", + type="type", + description=polarion_api.HtmlContent(markupsafe.Markup("")), ) del base_object.mc.converter_session["uuid2"] @@ -783,30 +769,17 @@ def test_update_work_items( get_work_item_mock, ) - base_object.pw.compare_and_update_work_items( - base_object.mc.converter_session - ) - assert ( - base_object.pw.project_client.work_items.links.get_all.call_count - == 0 - ) - assert ( - base_object.pw.project_client.work_items.links.delete.call_count - == 0 - ) - assert ( - base_object.pw.project_client.work_items.links.create.call_count - == 0 - ) + base_object.pw.compare_and_update_work_items(base_object.mc.converter_session) + assert base_object.pw.project_client.work_items.links.get_all.call_count == 0 + assert base_object.pw.project_client.work_items.links.delete.call_count == 0 + assert base_object.pw.project_client.work_items.links.create.call_count == 0 assert base_object.pw.project_client.work_items.update.call_count == 1 assert base_object.pw.project_client.work_items.get.call_count == 1 assert ( base_object.pw.project_client.work_items.attachments.get_all.call_count # pylint: disable=line-too-long == 0 ) - work_item = base_object.pw.project_client.work_items.update.call_args[ - 0 - ][0] + work_item = base_object.pw.project_client.work_items.update.call_args[0][0] assert isinstance(work_item, data_model.CapellaWorkItem) assert work_item.id == "Obj-1" assert work_item.title == "Fake 1" @@ -839,17 +812,15 @@ def test_update_deleted_work_item( base_object.pw.load_polarion_work_item_map() - base_object.mc.converter_session["uuid1"].work_item = ( - data_model.CapellaWorkItem( - id="Obj-1", - type="type", - uuid_capella="uuid1", - status="open", - title="Something", - description=polarion_api.HtmlContent( - markupsafe.Markup("Test") - ), - ) + base_object.mc.converter_session[ + "uuid1" + ].work_item = data_model.CapellaWorkItem( + id="Obj-1", + type="type", + uuid_capella="uuid1", + status="open", + title="Something", + description=polarion_api.HtmlContent(markupsafe.Markup("Test")), ) del base_object.mc.converter_session["uuid2"] @@ -861,22 +832,14 @@ def test_update_deleted_work_item( "get", get_work_item_mock, ) - base_object.pw.delete_orphaned_work_items( - base_object.mc.converter_session - ) + base_object.pw.delete_orphaned_work_items(base_object.mc.converter_session) assert base_object.pw.project_client.work_items.update.called is False - base_object.pw.create_missing_work_items( - base_object.mc.converter_session - ) + base_object.pw.create_missing_work_items(base_object.mc.converter_session) assert base_object.pw.project_client.work_items.create.called is False - base_object.pw.compare_and_update_work_items( - base_object.mc.converter_session - ) - work_item = base_object.pw.project_client.work_items.update.call_args[ - 0 - ][0] + base_object.pw.compare_and_update_work_items(base_object.mc.converter_session) + work_item = base_object.pw.project_client.work_items.update.call_args[0][0] assert isinstance(work_item, data_model.CapellaWorkItem) assert work_item.status == "open" @@ -896,13 +859,9 @@ def test_create_new_work_item(base_object: BaseObjectContainer): ) base_object.pw.load_polarion_work_item_map() - base_object.pw.create_missing_work_items( - base_object.mc.converter_session - ) + base_object.pw.create_missing_work_items(base_object.mc.converter_session) - polarion_api_create_work_items = ( - base_object.pw.project_client.work_items.create - ) + polarion_api_create_work_items = base_object.pw.project_client.work_items.create assert polarion_api_create_work_items.call_count == 1 assert len(polarion_api_create_work_items.call_args[0][0]) == 1 @@ -911,9 +870,7 @@ def test_create_new_work_item(base_object: BaseObjectContainer): assert work_item.id == "AUTO-0" assert len(base_object.pw.polarion_data_repo) == 2 assert ( - base_object.pw.polarion_data_repo.get_work_item_by_capella_uuid( - "uuid2" - ).id + base_object.pw.polarion_data_repo.get_work_item_by_capella_uuid("uuid2").id == "AUTO-0" ) @@ -935,9 +892,7 @@ def test_update_work_items_filters_work_items_with_same_checksum( del base_object.mc.converter_session["uuid2"] - base_object.pw.compare_and_update_work_items( - base_object.mc.converter_session - ) + base_object.pw.compare_and_update_work_items(base_object.mc.converter_session) assert base_object.pw.project_client.work_items.update.call_count == 0 @@ -960,36 +915,25 @@ def test_update_work_items_same_checksum_force( del base_object.mc.converter_session["uuid2"] - base_object.pw.compare_and_update_work_items( - base_object.mc.converter_session - ) + base_object.pw.compare_and_update_work_items(base_object.mc.converter_session) assert base_object.pw.project_client.work_items.update.call_count == 1 @staticmethod def test_update_links_with_no_elements(base_object: BaseObjectContainer): - base_object.pw.polarion_data_repo = ( - polarion_repo.PolarionDataRepository() - ) + base_object.pw.polarion_data_repo = polarion_repo.PolarionDataRepository() base_object.mc.converter_session = {} - base_object.pw.compare_and_update_work_items( - base_object.mc.converter_session - ) + base_object.pw.compare_and_update_work_items(base_object.mc.converter_session) - assert ( - base_object.pw.project_client.work_items.links.get_all.call_count - == 0 - ) + assert base_object.pw.project_client.work_items.links.get_all.call_count == 0 @staticmethod def test_update_links(base_object: BaseObjectContainer): link = polarion_api.WorkItemLink( "Obj-1", "Obj-2", "attribute", True, "project_id" ) - work_item = ( - base_object.pw.polarion_data_repo.get_work_item_by_capella_uuid( - "uuid1" - ) + work_item = base_object.pw.polarion_data_repo.get_work_item_by_capella_uuid( + "uuid1" ) work_item.linked_work_items = [link] base_object.pw.polarion_data_repo.update_work_items( @@ -1002,13 +946,13 @@ def test_update_links(base_object: BaseObjectContainer): ) ] ) - base_object.mc.converter_session["uuid2"].work_item = ( - data_model.CapellaWorkItem( - id="Obj-2", - uuid_capella="uuid2", - status="open", - type="fakeModelObject", - ) + base_object.mc.converter_session[ + "uuid2" + ].work_item = data_model.CapellaWorkItem( + id="Obj-2", + uuid_capella="uuid2", + status="open", + type="fakeModelObject", ) for data in base_object.mc.converter_session.values(): data.type_config.links[0].polarion_role = "attribute" @@ -1025,15 +969,11 @@ def test_update_links(base_object: BaseObjectContainer): generate_grouped_links_custom_fields=True, ) - work_item_1 = ( - base_object.pw.polarion_data_repo.get_work_item_by_capella_uuid( - "uuid1" - ) + work_item_1 = base_object.pw.polarion_data_repo.get_work_item_by_capella_uuid( + "uuid1" ) - work_item_2 = ( - base_object.pw.polarion_data_repo.get_work_item_by_capella_uuid( - "uuid2" - ) + work_item_2 = base_object.pw.polarion_data_repo.get_work_item_by_capella_uuid( + "uuid2" ) work_item_1.linked_work_items_truncated = True work_item_2.linked_work_items_truncated = True @@ -1043,34 +983,21 @@ def test_update_links(base_object: BaseObjectContainer): work_item_2, ) - base_object.pw.compare_and_update_work_items( - base_object.mc.converter_session - ) + base_object.pw.compare_and_update_work_items(base_object.mc.converter_session) links = ( base_object.pw.project_client.work_items.links.get_all.call_args_list # pylint: disable=line-too-long ) - assert ( - base_object.pw.project_client.work_items.links.get_all.call_count - == 2 - ) + assert base_object.pw.project_client.work_items.links.get_all.call_count == 2 assert [links[0][0][0], links[1][0][0]] == ["Obj-1", "Obj-2"] - new_links = ( - base_object.pw.project_client.work_items.links.create.call_args[0][ - 0 - ] - ) - assert ( - base_object.pw.project_client.work_items.links.create.call_count - == 1 - ) + new_links = base_object.pw.project_client.work_items.links.create.call_args[0][ + 0 + ] + assert base_object.pw.project_client.work_items.links.create.call_count == 1 assert new_links == [expected_new_link] - assert ( - base_object.pw.project_client.work_items.links.delete.call_count - == 1 - ) - assert base_object.pw.project_client.work_items.links.delete.call_args[ + assert base_object.pw.project_client.work_items.links.delete.call_count == 1 + assert base_object.pw.project_client.work_items.links.delete.call_args[0][ 0 - ][0] == [link] + ] == [link] @staticmethod def test_patch_work_item_grouped_links( @@ -1087,20 +1014,18 @@ def test_patch_work_item_grouped_links( ) for work_item in dummy_work_items.values() } - base_object.pw.polarion_data_repo = ( - polarion_repo.PolarionDataRepository( - [ - data_model.CapellaWorkItem( - id="Obj-0", uuid_capella="uuid0", status="open" - ), - data_model.CapellaWorkItem( - id="Obj-1", uuid_capella="uuid1", status="open" - ), - data_model.CapellaWorkItem( - id="Obj-2", uuid_capella="uuid2", status="open" - ), - ] - ) + base_object.pw.polarion_data_repo = polarion_repo.PolarionDataRepository( + [ + data_model.CapellaWorkItem( + id="Obj-0", uuid_capella="uuid0", status="open" + ), + data_model.CapellaWorkItem( + id="Obj-1", uuid_capella="uuid1", status="open" + ), + data_model.CapellaWorkItem( + id="Obj-2", uuid_capella="uuid2", status="open" + ), + ] ) mock_create_links = mock.MagicMock() monkeypatch.setattr( @@ -1142,9 +1067,7 @@ def mock_back_link(converter_data, back_links): base_object.pw.polarion_data_repo, generate_grouped_links_custom_fields=True, ) - base_object.pw.compare_and_update_work_items( - base_object.mc.converter_session - ) + base_object.pw.compare_and_update_work_items(base_object.mc.converter_session) update_work_item_calls = ( base_object.pw.project_client.work_items.update.call_args_list ) @@ -1152,18 +1075,9 @@ def mock_back_link(converter_data, back_links): mock_grouped_links_calls = mock_grouped_links.call_args_list assert len(mock_grouped_links_calls) == 3 assert mock_grouped_links_reverse.call_count == 3 - assert ( - mock_grouped_links_calls[0][0][0].work_item - == dummy_work_items["uuid0"] - ) - assert ( - mock_grouped_links_calls[1][0][0].work_item - == dummy_work_items["uuid1"] - ) - assert ( - mock_grouped_links_calls[2][0][0].work_item - == dummy_work_items["uuid2"] - ) + assert mock_grouped_links_calls[0][0][0].work_item == dummy_work_items["uuid0"] + assert mock_grouped_links_calls[1][0][0].work_item == dummy_work_items["uuid1"] + assert mock_grouped_links_calls[2][0][0].work_item == dummy_work_items["uuid2"] work_item_0 = update_work_item_calls[0][0][0] del work_item_0.additional_attributes["checksum"] work_item_1 = update_work_item_calls[1][0][0] @@ -1207,9 +1121,7 @@ def test_maintain_grouped_links_attributes( mock_model, ) for work_item in dummy_work_items.values(): - converter_data = data_session.ConverterData( - "test", config, [], work_item - ) + converter_data = data_session.ConverterData("test", config, [], work_item) link_serializer._link_field_groups["attribute"] = ( work_item.linked_work_items ) @@ -1219,15 +1131,11 @@ def test_maintain_grouped_links_attributes( del dummy_work_items["uuid2"].additional_attributes["uuid_capella"] assert ( - dummy_work_items["uuid0"].additional_attributes.pop("attribute")[ - "value" - ] + dummy_work_items["uuid0"].additional_attributes.pop("attribute")["value"] == HTML_LINK_0["attribute"] ) assert ( - dummy_work_items["uuid1"].additional_attributes.pop("attribute")[ - "value" - ] + dummy_work_items["uuid1"].additional_attributes.pop("attribute")["value"] == HTML_LINK_1["attribute"] ) assert dummy_work_items["uuid0"].additional_attributes == {} @@ -1270,9 +1178,7 @@ def test_maintain_grouped_links_attributes_with_role_prefix( ) for work_item in dummy_work_items.values(): - converter_data = data_session.ConverterData( - "test", config, [], work_item - ) + converter_data = data_session.ConverterData("test", config, [], work_item) if work_item.uuid_capella == "uuid0": link_serializer._link_field_groups["attribute"] = ( work_item.linked_work_items @@ -1306,12 +1212,8 @@ def test_grouped_links_attributes_different_link_field_in_config( reverse_field="attribute1_reverse", ) ) - converter_data_1.capella_element.attribute = ( - converter_data_2.capella_element - ) - converter_data_1.capella_element.attribute1 = ( - converter_data_2.capella_element - ) + converter_data_1.capella_element.attribute = converter_data_2.capella_element + converter_data_1.capella_element.attribute1 = converter_data_2.capella_element expected_html = ( "