From 946af3a4c243dbb8dfc3e60e218fecb85cc539c9 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Wed, 31 Jul 2024 16:47:49 +0200 Subject: [PATCH 01/19] ci: Update hooks and add dependencies to mypy hook --- .pre-commit-config.yaml | 16 ++++++++++++---- pyproject.toml | 4 ++-- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 359cb920..b93d2c5d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ default_install_hook_types: [commit-msg, pre-commit] default_stages: [commit, merge-commit] repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: check-added-large-files - id: check-ast @@ -26,7 +26,7 @@ repos: - id: fix-byte-order-marker - id: trailing-whitespace - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.2.0 + rev: 24.4.2 hooks: - id: black - repo: https://github.com/PyCQA/isort @@ -47,12 +47,20 @@ repos: additional_dependencies: - pydocstyle[toml] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.8.0 + rev: v1.11.1 hooks: - id: mypy additional_dependencies: + - bidict + - cairosvg + - capellambse==0.5.69 + - click + - jinja2 + - polarion-rest-api-client==1.1.0 + - pydantic - types-requests - types-PyYAML + exclude: tests - repo: https://github.com/Lucas-C/pre-commit-hooks rev: v1.5.5 hooks: @@ -97,7 +105,7 @@ repos: - --comment-style - "..| |" - repo: https://github.com/fsfe/reuse-tool - rev: v3.0.1 + rev: v4.0.3 hooks: - id: reuse - repo: https://github.com/qoomon/git-conventional-commits diff --git a/pyproject.toml b/pyproject.toml index 9261f5d2..f62fe10b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,8 +28,8 @@ classifiers = [ "Programming Language :: Python :: 3.12", ] dependencies = [ - "capellambse>=0.5,<0.6", - "capellambse_context_diagrams", + "capellambse>=0.5.69,<0.6", + "capellambse_context_diagrams>=0.3.1,<0.4", "click", "PyYAML", "polarion-rest-api-client==1.1.1", From b14eb5a1f1f20c9d598f8b8a70cdd2aacab63db7 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Wed, 31 Jul 2024 16:48:00 +0200 Subject: [PATCH 02/19] ci: Please mypy hooks --- capella2polarion/connectors/polarion_repo.py | 15 +++--- .../connectors/polarion_worker.py | 52 ++++++++++--------- .../converters/element_converter.py | 29 ++++++++--- capella2polarion/converters/link_converter.py | 19 ++++--- tests/test_elements.py | 6 +-- 5 files changed, 69 insertions(+), 52 deletions(-) diff --git a/capella2polarion/connectors/polarion_repo.py b/capella2polarion/connectors/polarion_repo.py index f40f70ca..c31ce7b9 100644 --- a/capella2polarion/connectors/polarion_repo.py +++ b/capella2polarion/connectors/polarion_repo.py @@ -32,6 +32,7 @@ def __init__( { work_item.uuid_capella: work_item.id for work_item in polarion_work_items + if work_item.id is not None }, ) self._id_mapping.on_dup = bidict.OnDup( @@ -50,11 +51,9 @@ def __sizeof__(self) -> int: """Return the amount of registered Capella UUIDs.""" return len(self._id_mapping) - def __getitem__( - self, item: str - ) -> tuple[str, data_models.CapellaWorkItem]: - """Return the polarion ID and work_item for a given Capella UUID.""" - return self._id_mapping[item], self._work_items[item] + def __getitem__(self, item: str) -> data_models.CapellaWorkItem: + """Return the work_item for a given Capella UUID.""" + return self._work_items[item] def __iter__(self) -> cabc.Iterator[str]: """Iterate all Capella UUIDs.""" @@ -89,12 +88,10 @@ def get_work_item_by_polarion_id( self.get_capella_uuid(work_item_id) # type: ignore ) - def update_work_items( - self, - work_items: list[data_models.CapellaWorkItem], - ): + def update_work_items(self, work_items: list[data_models.CapellaWorkItem]): """Update all mappings for the given Work Items.""" for work_item in work_items: + assert work_item.id is not None if uuid_capella := self._id_mapping.inverse.get(work_item.id): del self._id_mapping[uuid_capella] del self._work_items[uuid_capella] diff --git a/capella2polarion/connectors/polarion_worker.py b/capella2polarion/connectors/polarion_worker.py index e6b22371..686f77f1 100644 --- a/capella2polarion/connectors/polarion_worker.py +++ b/capella2polarion/connectors/polarion_worker.py @@ -136,7 +136,6 @@ def delete_orphaned_work_items( If the delete flag is set to ``False`` in the context work items are marked as ``to be deleted`` via the status attribute. """ - existing_work_items = { uuid for uuid, _, work_item in self.polarion_data_repo.items() @@ -192,8 +191,9 @@ def compare_and_update_work_item( new = converter_data.work_item assert new is not None uuid = new.uuid_capella - _, old = self.polarion_data_repo[uuid] + old: data_models.CapellaWorkItem | None = self.polarion_data_repo[uuid] assert old is not None + assert isinstance(old.id, str) new.calculate_checksum() if not self.force_update and new == old: @@ -204,12 +204,15 @@ def compare_and_update_work_item( "Update work item %r for model element %s %r...", *log_args ) - if old.get_current_checksum()[0] != "{": # XXX: Remove in next release - old_checksums = {"__C2P__WORK_ITEM": old.get_current_checksum()} + old_checksum = old.get_current_checksum() or "None" + if old_checksum[0] != "{": # XXX: Remove in next release + old_checksums = {"__C2P__WORK_ITEM": old_checksum} else: - old_checksums = json.loads(old.get_current_checksum()) + old_checksums = json.loads(old_checksum) - new_checksums = json.loads(new.get_current_checksum()) + new_checksum = new.get_current_checksum() + assert new_checksum is not None + new_checksums = json.loads(new_checksum) new_work_item_check_sum = new_checksums.pop("__C2P__WORK_ITEM") old_work_item_check_sum = old_checksums.pop("__C2P__WORK_ITEM") @@ -220,6 +223,8 @@ def compare_and_update_work_item( old = self.project_client.work_items.get( old.id, work_item_cls=data_models.CapellaWorkItem ) + assert old is not None + assert old.id is not None if old.attachments: old_attachments = ( self.project_client.work_items.attachments.get_all( @@ -370,10 +375,14 @@ def update_attachments( all attachments of the new work item should have IDs. """ new_attachment_dict = { - attachment.file_name: attachment for attachment in new.attachments + attachment.file_name: attachment + for attachment in new.attachments + if attachment.file_name is not None } old_attachment_dict = { - attachment.file_name: attachment for attachment in old_attachments + attachment.file_name: attachment + for attachment in old_attachments + if attachment.file_name is not None } created = False @@ -396,22 +405,21 @@ def update_attachments( old_attachment_dict[file_name] ) - if new_attachments := list( - map( - new_attachment_dict.get, - new_attachment_file_names - old_attachment_file_names, - ) - ): + new_attachments: cabc.Iterable[polarion_api.WorkItemAttachment] = map( + new_attachment_dict.get, # type:ignore[arg-type] + new_attachment_file_names - old_attachment_file_names, + ) + if new_attachments := list(filter(None, new_attachments)): self.project_client.work_items.attachments.create(new_attachments) created = True - attachments_for_update = {} + attachments_for_update: dict[str, polarion_api.WorkItemAttachment] = {} for common_attachment_file_name in ( old_attachment_file_names & new_attachment_file_names ): attachment = new_attachment_dict[common_attachment_file_name] attachment.id = old_attachment_dict[common_attachment_file_name].id - if ( + if attachment.file_name is not None and ( new_checksums.get(attachment.file_name) != old_checksums.get(attachment.file_name) or self.force_update @@ -449,14 +457,10 @@ def get_missing_link_ids( @staticmethod def _get_link_id(link: polarion_api.WorkItemLink) -> str: - return "/".join( - ( - link.primary_work_item_id, - link.role, - link.secondary_work_item_project, - link.secondary_work_item_id, - ) - ) + secondary_id = link.secondary_work_item_id + if link.secondary_work_item_project: + secondary_id = f"{link.secondary_work_item_project}/{secondary_id}" + return "/".join((link.primary_work_item_id, link.role, secondary_id)) def compare_and_update_work_items( self, converter_session: data_session.ConverterSession diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index 3166df03..8f69f5a7 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -19,8 +19,9 @@ import polarion_rest_api_client as polarion_api from capellambse import helpers as chelpers from capellambse.model import common +from capellambse.model import diagram as diag from capellambse.model.crosslayer import interaction -from capellambse.model.layers import oa +from capellambse.model.layers import ctx, la, oa from lxml import etree from capella2polarion import data_models @@ -32,9 +33,15 @@ ) RE_CAMEL_CASE_2ND_WORD_PATTERN = re.compile(r"([a-z]+)([A-Z][a-z]+)") -PrePostConditionElement = t.Union[ +PrePostConditionElement: t.TypeAlias = t.Union[ oa.OperationalCapability, interaction.Scenario ] +PrePostConditionElementTypes = ( + oa.OperationalCapability, + ctx.Capability, + la.CapabilityRealization, + interaction.Scenario, +) logger = logging.getLogger(__name__) C2P_IMAGE_PREFIX = "__C2P__" @@ -94,7 +101,7 @@ def __init__( def serialize_all(self) -> list[data_models.CapellaWorkItem]: """Serialize all items of the converter_session.""" - work_items = [self.serialize(uuid) for uuid in self.converter_session] + work_items = (self.serialize(uuid) for uuid in self.converter_session) return list(filter(None, work_items)) def serialize(self, uuid: str) -> data_models.CapellaWorkItem | None: @@ -144,6 +151,7 @@ def _add_attachment( work_item: data_models.CapellaWorkItem, attachment: polarion_api.WorkItemAttachment, ): + assert attachment.file_name is not None attachment.work_item_id = work_item.id or "" work_item.attachments.append(attachment) if attachment.mime_type == "image/svg+xml": @@ -205,7 +213,7 @@ def _render_jinja_template( converter_data: data_session.ConverterData, ): env = self._get_jinja_env(str(template_folder)) - template = env.get_template(template_path) + template = env.get_template(str(template_path)) rendered_jinja = template.render( object=converter_data.capella_element, model=self.model, @@ -287,7 +295,7 @@ def _draw_additional_attributes_diagram( } def _sanitize_linked_text( - self, obj: common.GenericElement + self, obj: common.GenericElement | diag.Diagram ) -> tuple[ list[str], markupsafe.Markup, list[polarion_api.WorkItemAttachment] ]: @@ -304,7 +312,9 @@ def _sanitize_linked_text( return self._sanitize_text(obj, linked_text) def _sanitize_text( - self, obj: common.GenericElement, text: markupsafe.Markup | str + self, + obj: common.GenericElement | diag.Diagram, + text: markupsafe.Markup | str, ) -> tuple[ list[str], markupsafe.Markup, list[polarion_api.WorkItemAttachment] ]: @@ -395,7 +405,7 @@ def _replace_markup( def _get_requirement_types_text( self, - obj: common.GenericElement, + obj: common.GenericElement | diag.Diagram, ) -> dict[str, dict[str, str]]: type_texts = collections.defaultdict(list) for req in getattr(obj, "requirements", []): @@ -440,8 +450,9 @@ def __generic_work_item( description_type="text/html", description=value, status="open", - **requirement_types, + **requirement_types, # type:ignore[arg-type] ) + assert converter_data.work_item is not None for attachment in attachments: self._add_attachment(converter_data.work_item, attachment) @@ -455,6 +466,7 @@ def _diagram( """Serialize a diagram for Polarion.""" diagram = converter_data.capella_element assert converter_data.work_item is not None + assert isinstance(diagram, diag.Diagram) work_item_id = converter_data.work_item.id diagram_html, attachment = self._draw_diagram_svg( @@ -482,6 +494,7 @@ def _include_pre_and_post_condition( obj = converter_data.capella_element assert hasattr(obj, "precondition"), "Missing PreCondition Attribute" assert hasattr(obj, "postcondition"), "Missing PostCondition Attribute" + assert isinstance(obj, PrePostConditionElementTypes) def get_condition(cap: PrePostConditionElement, name: str) -> str: if not (condition := getattr(cap, name)): diff --git a/capella2polarion/converters/link_converter.py b/capella2polarion/converters/link_converter.py index a618b087..cab03ab4 100644 --- a/capella2polarion/converters/link_converter.py +++ b/capella2polarion/converters/link_converter.py @@ -65,6 +65,7 @@ def create_links_for_work_item( serializer = self.serializers.get(link_config.capella_attr) role_id = link_config.polarion_role try: + assert work_item.id is not None if serializer: new_links.extend( serializer(obj, work_item.id, role_id, {}) @@ -135,7 +136,7 @@ def _get_work_item_ids( def _handle_description_reference_links( self, - obj: common.GenericElement, + obj: common.GenericElement | diag.Diagram, work_item_id: str, role_id: str, links: dict[str, polarion_api.WorkItemLink], @@ -146,20 +147,21 @@ def _handle_description_reference_links( def _handle_diagram_reference_links( self, - obj: diag.Diagram, + diagram: common.GenericElement | diag.Diagram, work_item_id: str, role_id: str, links: dict[str, polarion_api.WorkItemLink], ) -> list[polarion_api.WorkItemLink]: + assert isinstance(diagram, diag.Diagram) try: - refs = set(self._collect_uuids(obj.nodes)) + refs = set(self._collect_uuids(diagram.nodes)) refs = set(self._get_work_item_ids(work_item_id, refs, role_id)) ref_links = self._create(work_item_id, role_id, refs, links) except Exception as err: logger.exception( "Could not create links for diagram %r, " "because an error occured %s", - obj._short_repr_(), + diagram._short_repr_(), err, ) ref_links = [] @@ -282,18 +284,19 @@ def _create_link_fields( obj._short_repr_(), ) + uuids: cabc.Iterable[str] if isinstance(attr, common.ElementList): uuids = attr.by_uuid # type: ignore[assignment] else: assert hasattr(attr, "uuid") uuids = [attr.uuid] + assert work_item.id is not None work_item_ids = list( self._get_work_item_ids(work_item.id, uuids, attr_name) ) - include_map[f"{link_id}:{display_name}:{attr_name}"] = ( - work_item_ids - ) + include_key = f"{link_id}:{display_name}:{attr_name}" + include_map[include_key] = work_item_ids work_item.additional_attributes[role] = { "type": "text/html", @@ -378,7 +381,7 @@ def _sorted_unordered_html_list( def _resolve_attribute( - obj: common.GenericElement, attr_id: str + obj: common.GenericElement | diag.Diagram, attr_id: str ) -> common.ElementList[common.GenericElement] | common.GenericElement: attr_name, _, map_id = attr_id.partition(".") objs = getattr(obj, attr_name) diff --git a/tests/test_elements.py b/tests/test_elements.py index 1c8e88eb..00a0132e 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -959,7 +959,7 @@ 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["uuid1"] + work_item = base_object.pw.polarion_data_repo["uuid1"] work_item.linked_work_items = [link] base_object.pw.polarion_data_repo.update_work_items( [ @@ -1000,10 +1000,10 @@ def test_update_links(base_object: BaseObjectContainer): ) work_item_1 = data_models.CapellaWorkItem( - **base_object.pw.polarion_data_repo["uuid1"][1].to_dict() + **base_object.pw.polarion_data_repo["uuid1"].to_dict() ) work_item_2 = data_models.CapellaWorkItem( - **base_object.pw.polarion_data_repo["uuid2"][1].to_dict() + **base_object.pw.polarion_data_repo["uuid2"].to_dict() ) work_item_1.linked_work_items_truncated = True work_item_2.linked_work_items_truncated = True From 8f85f4612d5f8fbabeed95f3c66fb4f83b4b2599 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Wed, 31 Jul 2024 17:56:21 +0200 Subject: [PATCH 03/19] fix: Make tests green again --- capella2polarion/converters/element_converter.py | 4 ++-- tests/test_cli.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index 8f69f5a7..baaeff1d 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -494,9 +494,9 @@ def _include_pre_and_post_condition( obj = converter_data.capella_element assert hasattr(obj, "precondition"), "Missing PreCondition Attribute" assert hasattr(obj, "postcondition"), "Missing PostCondition Attribute" - assert isinstance(obj, PrePostConditionElementTypes) + assert not isinstance(obj, diag.Diagram) - def get_condition(cap: PrePostConditionElement, name: str) -> str: + def get_condition(cap: common.GenericElement, name: str) -> str: if not (condition := getattr(cap, name)): return "" _, value, _ = self._sanitize_linked_text(condition) diff --git a/tests/test_cli.py b/tests/test_cli.py index 7894f405..be6fc804 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -64,7 +64,7 @@ def test_migrate_model_elements(monkeypatch: pytest.MonkeyPatch): "--polarion-url", "https://www.czy.de", "--polarion-pat", - "AlexandersPrivateAcessToken", + "PrivateAcessToken", "--polarion-delete-work-items", "--capella-model", json.dumps(TEST_MODEL), From 62c2a30f67fc21d4f19f5d061f2ebabe9cf73bd5 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Thu, 1 Aug 2024 18:36:13 +0200 Subject: [PATCH 04/19] fix: Log work items without id during link creation --- capella2polarion/converters/model_converter.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/capella2polarion/converters/model_converter.py b/capella2polarion/converters/model_converter.py index d7c79b38..64c98673 100644 --- a/capella2polarion/converters/model_converter.py +++ b/capella2polarion/converters/model_converter.py @@ -152,7 +152,14 @@ def generate_work_item_links( ) continue - assert converter_data.work_item.id is not None + if converter_data.work_item.id is None: + logger.error( + "Expected WorkItem to be created before creating " + "links: %s.", + uuid, + ) + continue + if local_back_links := back_links.get(converter_data.work_item.id): link_serializer.create_grouped_back_link_fields( converter_data.work_item, local_back_links From fcfe7577a93e45e53342e880d6bd220f31cae9ba Mon Sep 17 00:00:00 2001 From: ewuerger Date: Thu, 22 Aug 2024 12:08:33 +0200 Subject: [PATCH 05/19] ci: Fix some mypy errors --- .pre-commit-config.yaml | 2 +- capella2polarion/connectors/polarion_repo.py | 4 ---- .../connectors/polarion_worker.py | 4 +++- .../converters/converter_config.py | 1 + .../converters/document_config.py | 19 ++++++++++--------- .../converters/element_converter.py | 1 + capella2polarion/converters/link_converter.py | 2 +- tests/test_elements.py | 18 +++++++++++++----- 8 files changed, 30 insertions(+), 21 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index b93d2c5d..4a1efb96 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -56,7 +56,7 @@ repos: - capellambse==0.5.69 - click - jinja2 - - polarion-rest-api-client==1.1.0 + - polarion-rest-api-client==1.1.1 - pydantic - types-requests - types-PyYAML diff --git a/capella2polarion/connectors/polarion_repo.py b/capella2polarion/connectors/polarion_repo.py index c31ce7b9..93204140 100644 --- a/capella2polarion/connectors/polarion_repo.py +++ b/capella2polarion/connectors/polarion_repo.py @@ -51,10 +51,6 @@ def __sizeof__(self) -> int: """Return the amount of registered Capella UUIDs.""" return len(self._id_mapping) - def __getitem__(self, item: str) -> data_models.CapellaWorkItem: - """Return the work_item for a given Capella UUID.""" - return self._work_items[item] - def __iter__(self) -> cabc.Iterator[str]: """Iterate all Capella UUIDs.""" return self._id_mapping.__iter__() diff --git a/capella2polarion/connectors/polarion_worker.py b/capella2polarion/connectors/polarion_worker.py index 686f77f1..999c03fa 100644 --- a/capella2polarion/connectors/polarion_worker.py +++ b/capella2polarion/connectors/polarion_worker.py @@ -191,7 +191,9 @@ def compare_and_update_work_item( new = converter_data.work_item assert new is not None uuid = new.uuid_capella - old: data_models.CapellaWorkItem | None = self.polarion_data_repo[uuid] + old: data_models.CapellaWorkItem | None = ( + self.polarion_data_repo.get_work_item_by_capella_uuid(uuid) + ) assert old is not None assert isinstance(old.id, str) diff --git a/capella2polarion/converters/converter_config.py b/capella2polarion/converters/converter_config.py index 21fc942f..ae0d6aae 100644 --- a/capella2polarion/converters/converter_config.py +++ b/capella2polarion/converters/converter_config.py @@ -370,6 +370,7 @@ def _filter_context_diagram_config( def _filter_links( c_type: str, links: list[LinkConfig], is_global: bool = False ) -> list[LinkConfig]: + c_class: type[common.ModelObject | diagram.Diagram] if c_type == "diagram": c_class = diagram.Diagram else: diff --git a/capella2polarion/converters/document_config.py b/capella2polarion/converters/document_config.py index 6a936666..d2c0fb2d 100644 --- a/capella2polarion/converters/document_config.py +++ b/capella2polarion/converters/document_config.py @@ -1,15 +1,16 @@ # Copyright DB InfraGO AG and contributors # SPDX-License-Identifier: Apache-2.0 """Module with classes and a loader for document rendering configs.""" +import collections.abc as cabc import logging import pathlib import typing as t import capellambse import jinja2 -import polarion_rest_api_client as polarion_api import pydantic import yaml +from polarion_rest_api_client import data_models from capella2polarion import data_models from capella2polarion.converters import polarion_html_helper @@ -56,7 +57,7 @@ class BaseDocumentRenderingConfig(pydantic.BaseModel): work_item_layouts: dict[str, WorkItemLayout] = pydantic.Field( default_factory=dict ) - instances: list[DocumentRenderingInstance] + instances: cabc.Sequence[DocumentRenderingInstance] class FullAuthorityDocumentRenderingConfig(BaseDocumentRenderingConfig): @@ -69,7 +70,7 @@ class MixedAuthorityDocumentRenderingConfig(BaseDocumentRenderingConfig): """Mixed authority document with multiple auto generated sections.""" sections: dict[str, str] - instances: list[SectionBasedDocumentRenderingInstance] + instances: cabc.Sequence[SectionBasedDocumentRenderingInstance] class DocumentConfigs(pydantic.BaseModel): @@ -112,14 +113,14 @@ def read_config_file( def generate_work_item_layouts( configs: dict[str, WorkItemLayout] -) -> list[polarion_api.RenderingLayout]: +) -> list[data_models.RenderingLayout]: """Create polarion_api.RenderingLayouts for a given configuration.""" results = [] for _type, conf in configs.items(): if conf.show_title and conf.show_description: - layouter = polarion_api.data_models.Layouter.SECTION + layouter = data_models.Layouter.SECTION elif conf.show_description: - layouter = polarion_api.data_models.Layouter.PARAGRAPH + layouter = data_models.Layouter.PARAGRAPH else: if not conf.show_title: logger.warning( @@ -127,13 +128,13 @@ def generate_work_item_layouts( "For that reason, the title will be shown for %s.", _type, ) - layouter = polarion_api.data_models.Layouter.TITLE + layouter = data_models.Layouter.TITLE results.append( - polarion_api.RenderingLayout( + data_models.RenderingLayout( type=_type, layouter=layouter, label=polarion_html_helper.camel_case_to_words(_type), - properties=polarion_api.data_models.RenderingProperties( + properties=data_models.RenderingProperties( fields_at_start=conf.fields_at_start, fields_at_end=conf.fields_at_end, fields_at_end_as_table=conf.show_fields_as_table, diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index baaeff1d..1161a6ba 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -250,6 +250,7 @@ def __insert_diagram( ), None, ): + assert attachment.file_name is not None return polarion_html_helper.generate_image_html( diagram.name, attachment.file_name, diff --git a/capella2polarion/converters/link_converter.py b/capella2polarion/converters/link_converter.py index cab03ab4..e5537349 100644 --- a/capella2polarion/converters/link_converter.py +++ b/capella2polarion/converters/link_converter.py @@ -25,7 +25,7 @@ TYPE_RESOLVERS = {"Part": lambda obj: obj.type.uuid} _Serializer: t.TypeAlias = cabc.Callable[ - [common.GenericElement, str, str, dict[str, t.Any]], + [diag.Diagram | common.GenericElement, str, str, dict[str, t.Any]], list[polarion_api.WorkItemLink], ] diff --git a/tests/test_elements.py b/tests/test_elements.py index 00a0132e..a62ca1bd 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -959,7 +959,11 @@ 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["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( [ @@ -999,11 +1003,15 @@ def test_update_links(base_object: BaseObjectContainer): base_object.pw.polarion_data_repo ) - work_item_1 = data_models.CapellaWorkItem( - **base_object.pw.polarion_data_repo["uuid1"].to_dict() + work_item_1 = ( + base_object.pw.polarion_data_repo.get_work_item_by_capella_uuid( + "uuid1" + ) ) - work_item_2 = data_models.CapellaWorkItem( - **base_object.pw.polarion_data_repo["uuid2"].to_dict() + 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 From a5744e6e53fbfdd716544e1dcb4db800a85dd929 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Mon, 26 Aug 2024 04:17:11 +0200 Subject: [PATCH 06/19] ci: Fix type annotations --- capella2polarion/converters/document_renderer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/capella2polarion/converters/document_renderer.py b/capella2polarion/converters/document_renderer.py index 15a9dc68..80610212 100644 --- a/capella2polarion/converters/document_renderer.py +++ b/capella2polarion/converters/document_renderer.py @@ -470,7 +470,9 @@ def _render_mixed_authority_documents( def _render_full_authority_documents( self, - full_authority_configs, + full_authority_configs: list[ + document_config.FullAuthorityDocumentRenderingConfig + ], ): for config in full_authority_configs: rendering_layouts = document_config.generate_work_item_layouts( From 2ccc1c335e34d20b262cc3f35ce966281165c7f9 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Mon, 26 Aug 2024 04:17:23 +0200 Subject: [PATCH 07/19] ci: Update pre-commit --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4a1efb96..17935d0f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -26,7 +26,7 @@ repos: - id: fix-byte-order-marker - id: trailing-whitespace - repo: https://github.com/psf/black-pre-commit-mirror - rev: 24.4.2 + rev: 24.8.0 hooks: - id: black - repo: https://github.com/PyCQA/isort @@ -47,7 +47,7 @@ repos: additional_dependencies: - pydocstyle[toml] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.11.1 + rev: v1.11.2 hooks: - id: mypy additional_dependencies: From 9754321cf93ae5c99b5f6e3992cf814e745304a9 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Mon, 26 Aug 2024 04:47:00 +0200 Subject: [PATCH 08/19] fix: Apply suggestions from code review --- .../connectors/polarion_worker.py | 62 +++++++++++++------ .../converters/element_converter.py | 12 ---- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/capella2polarion/connectors/polarion_worker.py b/capella2polarion/connectors/polarion_worker.py index 999c03fa..1c725793 100644 --- a/capella2polarion/connectors/polarion_worker.py +++ b/capella2polarion/connectors/polarion_worker.py @@ -206,12 +206,7 @@ def compare_and_update_work_item( "Update work item %r for model element %s %r...", *log_args ) - old_checksum = old.get_current_checksum() or "None" - if old_checksum[0] != "{": # XXX: Remove in next release - old_checksums = {"__C2P__WORK_ITEM": old_checksum} - else: - old_checksums = json.loads(old_checksum) - + old_checksums = {"__C2P__WORK_ITEM": old.get_current_checksum() or ""} new_checksum = new.get_current_checksum() assert new_checksum is not None new_checksums = json.loads(new_checksum) @@ -245,7 +240,7 @@ def compare_and_update_work_item( work_item_changed |= self.update_attachments( new, old_checksums, new_checksums, old_attachments ) - except polarion_api.PolarionApiException as error: + except (polarion_api.PolarionApiException, ValueError) as error: logger.error( "Updating attachments for WorkItem %r (%s %s) failed. %s", *log_args, @@ -376,19 +371,25 @@ def update_attachments( Returns True if new attachments were created. After execution all attachments of the new work item should have IDs. """ - new_attachment_dict = { - attachment.file_name: attachment - for attachment in new.attachments - if attachment.file_name is not None - } - old_attachment_dict = { - attachment.file_name: attachment - for attachment in old_attachments - if attachment.file_name is not None - } + new_attachment_dict: dict[str, polarion_api.WorkItemAttachment] = {} + for attachment in new.attachments: + if attachment.file_name is None: + raise ValueError( + f"Found new attachment without filename: {new.id!r} with " + + attachment.id + ) + new_attachment_dict[attachment.file_name] = attachment - created = False + old_attachment_dict: dict[str, polarion_api.WorkItemAttachment] = {} + for attachment in old_attachments: + if attachment.file_name is None: + raise ValueError( + f"Found old attachment without filename: {new!r} with" + + attachment.id + ) + old_attachment_dict[attachment.file_name] = attachment + created = False for attachment in old_attachments: if attachment not in old_attachment_dict.values(): logger.error( @@ -447,10 +448,12 @@ def get_missing_link_ids( ) -> dict[str, polarion_api.WorkItemLink]: """Return an ID-Link dict of links present in left and not in right.""" left_id_map = { - CapellaPolarionWorker._get_link_id(link): link for link in left + CapellaPolarionWorker._get_link_id(link): link + for link in CapellaPolarionWorker._filter_all_link_ids(left) } right_id_map = { - CapellaPolarionWorker._get_link_id(link): link for link in right + CapellaPolarionWorker._get_link_id(link): link + for link in CapellaPolarionWorker._filter_all_link_ids(right) } return { lid: left_id_map[lid] @@ -464,6 +467,25 @@ def _get_link_id(link: polarion_api.WorkItemLink) -> str: secondary_id = f"{link.secondary_work_item_project}/{secondary_id}" return "/".join((link.primary_work_item_id, link.role, secondary_id)) + @staticmethod + def _filter_all_link_ids( + links: cabc.Iterable[polarion_api.WorkItemLink], + ) -> cabc.Iterator[polarion_api.WorkItemLink]: + for link in links: + if link.primary_work_item_id is None: + logger.error( # type: ignore[unreachable] + "Found Work Item Link without source ID: %r", link + ) + continue + + if link.secondary_work_item_id is None: + logger.error( # type: ignore[unreachable] + "Found Work Item Link without target ID: %r", link + ) + continue + + yield link + def compare_and_update_work_items( self, converter_session: data_session.ConverterSession ) -> None: diff --git a/capella2polarion/converters/element_converter.py b/capella2polarion/converters/element_converter.py index 1161a6ba..630c2304 100644 --- a/capella2polarion/converters/element_converter.py +++ b/capella2polarion/converters/element_converter.py @@ -20,8 +20,6 @@ from capellambse import helpers as chelpers from capellambse.model import common from capellambse.model import diagram as diag -from capellambse.model.crosslayer import interaction -from capellambse.model.layers import ctx, la, oa from lxml import etree from capella2polarion import data_models @@ -33,16 +31,6 @@ ) RE_CAMEL_CASE_2ND_WORD_PATTERN = re.compile(r"([a-z]+)([A-Z][a-z]+)") -PrePostConditionElement: t.TypeAlias = t.Union[ - oa.OperationalCapability, interaction.Scenario -] -PrePostConditionElementTypes = ( - oa.OperationalCapability, - ctx.Capability, - la.CapabilityRealization, - interaction.Scenario, -) - logger = logging.getLogger(__name__) C2P_IMAGE_PREFIX = "__C2P__" JINJA_RENDERED_IMG_CLS = "jinja-rendered-image" From 190746e12d5f29d8889dd1b5a363bbf5f274003f Mon Sep 17 00:00:00 2001 From: ewuerger Date: Mon, 26 Aug 2024 14:46:46 +0200 Subject: [PATCH 09/19] fix: Attachment old checksum generation --- capella2polarion/connectors/polarion_worker.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/capella2polarion/connectors/polarion_worker.py b/capella2polarion/connectors/polarion_worker.py index 1c725793..0a3fc3b9 100644 --- a/capella2polarion/connectors/polarion_worker.py +++ b/capella2polarion/connectors/polarion_worker.py @@ -206,7 +206,10 @@ def compare_and_update_work_item( "Update work item %r for model element %s %r...", *log_args ) - old_checksums = {"__C2P__WORK_ITEM": old.get_current_checksum() or ""} + if not (old_checksum := old.get_current_checksum() or ""): + old_checksum = '{"__C2P__WORK_ITEM": ""}' + old_checksums = json.loads(old_checksum) + new_checksum = new.get_current_checksum() assert new_checksum is not None new_checksums = json.loads(new_checksum) From e1f788fa9918da3d16721782cfac4eef3ebab211 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Mon, 26 Aug 2024 14:56:31 +0200 Subject: [PATCH 10/19] test: Remove overwriting of checksums --- tests/conftest.py | 3 +-- tests/test_elements.py | 3 --- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 050c0343..06f2429b 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -120,7 +120,7 @@ def base_object( model: capellambse.MelodyModel, monkeypatch: pytest.MonkeyPatch ) -> BaseObjectContainer: work_item = data_models.CapellaWorkItem( - id="Obj-1", uuid_capella="uuid1", status="open", checksum="123" + id="Obj-1", uuid_capella="uuid1", status="open" ) c2p_cli = cli.Capella2PolarionCli( debug=True, @@ -161,7 +161,6 @@ def base_object( id="Obj-1", uuid_capella="uuid1", status="open", - checksum="123", type="fakeModelObject", ), ), diff --git a/tests/test_elements.py b/tests/test_elements.py index a62ca1bd..60635b2f 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -743,7 +743,6 @@ def test_update_work_items( title="Something", description_type="text/html", description=markupsafe.Markup("Test"), - checksum="123", ) ] polarion_api_get_all_work_items = mock.MagicMock() @@ -820,7 +819,6 @@ def test_update_deleted_work_item( type="type", uuid_capella="uuid1", status="deleted", - checksum="123", ) ] polarion_api_get_all_work_items = mock.MagicMock() @@ -842,7 +840,6 @@ def test_update_deleted_work_item( title="Something", description_type="text/html", description=markupsafe.Markup("Test"), - checksum="123", ) ) From 721defb1e6178c00eefc1e1994f05d4205c5030a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ernst=20W=C3=BCrger?= Date: Tue, 27 Aug 2024 10:05:27 +0200 Subject: [PATCH 11/19] refactor: Apply suggestions from code review Co-authored-by: micha91 --- capella2polarion/connectors/polarion_worker.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/capella2polarion/connectors/polarion_worker.py b/capella2polarion/connectors/polarion_worker.py index 0a3fc3b9..8646e7f9 100644 --- a/capella2polarion/connectors/polarion_worker.py +++ b/capella2polarion/connectors/polarion_worker.py @@ -195,7 +195,7 @@ def compare_and_update_work_item( self.polarion_data_repo.get_work_item_by_capella_uuid(uuid) ) assert old is not None - assert isinstance(old.id, str) + assert old.id is not None new.calculate_checksum() if not self.force_update and new == old: @@ -206,9 +206,10 @@ def compare_and_update_work_item( "Update work item %r for model element %s %r...", *log_args ) - if not (old_checksum := old.get_current_checksum() or ""): - old_checksum = '{"__C2P__WORK_ITEM": ""}' - old_checksums = json.loads(old_checksum) + try: + old_checksums = json.loads(old.get_current_checksum() or "") + except json.JSONDecodeError: + old_checksums = {"__C2P__WORK_ITEM": ""} new_checksum = new.get_current_checksum() assert new_checksum is not None From 38efc8c200cba71693e7b63d2f342c64c6595e7d Mon Sep 17 00:00:00 2001 From: ewuerger Date: Tue, 27 Aug 2024 10:09:07 +0200 Subject: [PATCH 12/19] fix: Remove type annotation --- capella2polarion/connectors/polarion_worker.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/capella2polarion/connectors/polarion_worker.py b/capella2polarion/connectors/polarion_worker.py index 8646e7f9..2740c5a3 100644 --- a/capella2polarion/connectors/polarion_worker.py +++ b/capella2polarion/connectors/polarion_worker.py @@ -191,9 +191,7 @@ def compare_and_update_work_item( new = converter_data.work_item assert new is not None uuid = new.uuid_capella - old: data_models.CapellaWorkItem | None = ( - self.polarion_data_repo.get_work_item_by_capella_uuid(uuid) - ) + old = self.polarion_data_repo.get_work_item_by_capella_uuid(uuid) assert old is not None assert old.id is not None From ab192840ba56bfd386aa3b1be7cfed13c9619411 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Tue, 27 Aug 2024 10:29:23 +0200 Subject: [PATCH 13/19] fix: Raise a `ValueError` when a work item without ID is found --- capella2polarion/connectors/polarion_repo.py | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/capella2polarion/connectors/polarion_repo.py b/capella2polarion/connectors/polarion_repo.py index 93204140..09a3cf65 100644 --- a/capella2polarion/connectors/polarion_repo.py +++ b/capella2polarion/connectors/polarion_repo.py @@ -28,12 +28,13 @@ def __init__( ): if polarion_work_items is None: polarion_work_items = [] + + check_work_items(polarion_work_items) self._id_mapping = bidict.bidict( { work_item.uuid_capella: work_item.id for work_item in polarion_work_items - if work_item.id is not None - }, + }, # type: ignore[arg-type] ) self._id_mapping.on_dup = bidict.OnDup( key=bidict.DROP_OLD, val=bidict.DROP_OLD @@ -92,12 +93,12 @@ def update_work_items(self, work_items: list[data_models.CapellaWorkItem]): del self._id_mapping[uuid_capella] del self._work_items[uuid_capella] + check_work_items(work_items) self._id_mapping.update( { work_item.uuid_capella: work_item.id for work_item in work_items - if work_item.id is not None - } + } # type: ignore[arg-type] ) self._work_items.update( {work_item.uuid_capella: work_item for work_item in work_items} @@ -120,3 +121,13 @@ def remove_work_items_by_capella_uuid(self, uuids: cabc.Iterable[str]): workitems) as value. The project can be None and the None value means that the document is in the same project as the model sync work items. """ + + +def check_work_items(work_items: cabc.Iterable[data_models.CapellaWorkItem]): + """Raise a ``ValueError`` if any work item has no ID.""" + if work_item_without_id := next( + (wi for wi in work_items if wi.id is None), None + ): + raise ValueError( + f"Found Work Item without ID: {work_item_without_id.title!r}" + ) From 777aeab66ac06dc4b4795ab4181ba38bec25b9e4 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Tue, 27 Aug 2024 13:05:25 +0200 Subject: [PATCH 14/19] fix: Just import `polarion_rest_api_client` This needs [polarion-open-rest-api-client #47](https://github.com/DSD-DBS/polarion-rest-api-client/pull/47). --- capella2polarion/converters/document_config.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/capella2polarion/converters/document_config.py b/capella2polarion/converters/document_config.py index d2c0fb2d..39909e4c 100644 --- a/capella2polarion/converters/document_config.py +++ b/capella2polarion/converters/document_config.py @@ -8,9 +8,9 @@ import capellambse import jinja2 +import polarion_rest_api_client as polarion_api import pydantic import yaml -from polarion_rest_api_client import data_models from capella2polarion import data_models from capella2polarion.converters import polarion_html_helper @@ -113,14 +113,14 @@ def read_config_file( def generate_work_item_layouts( configs: dict[str, WorkItemLayout] -) -> list[data_models.RenderingLayout]: +) -> list[polarion_api.RenderingLayout]: """Create polarion_api.RenderingLayouts for a given configuration.""" results = [] for _type, conf in configs.items(): if conf.show_title and conf.show_description: - layouter = data_models.Layouter.SECTION + layouter = polarion_api.Layouter.SECTION elif conf.show_description: - layouter = data_models.Layouter.PARAGRAPH + layouter = polarion_api.Layouter.PARAGRAPH else: if not conf.show_title: logger.warning( @@ -128,13 +128,13 @@ def generate_work_item_layouts( "For that reason, the title will be shown for %s.", _type, ) - layouter = data_models.Layouter.TITLE + layouter = polarion_api.Layouter.TITLE results.append( - data_models.RenderingLayout( + polarion_api.RenderingLayout( type=_type, layouter=layouter, label=polarion_html_helper.camel_case_to_words(_type), - properties=data_models.RenderingProperties( + properties=polarion_api.RenderingProperties( fields_at_start=conf.fields_at_start, fields_at_end=conf.fields_at_end, fields_at_end_as_table=conf.show_fields_as_table, From a2bbabd5b96dc07cbb5f4ab97d1b07aa1abc7da6 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Tue, 27 Aug 2024 13:06:14 +0200 Subject: [PATCH 15/19] revert: Stop checking stuff that never happen Just assert the state. --- .../connectors/polarion_worker.py | 26 +++---------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/capella2polarion/connectors/polarion_worker.py b/capella2polarion/connectors/polarion_worker.py index 2740c5a3..8a8e0451 100644 --- a/capella2polarion/connectors/polarion_worker.py +++ b/capella2polarion/connectors/polarion_worker.py @@ -450,12 +450,10 @@ def get_missing_link_ids( ) -> dict[str, polarion_api.WorkItemLink]: """Return an ID-Link dict of links present in left and not in right.""" left_id_map = { - CapellaPolarionWorker._get_link_id(link): link - for link in CapellaPolarionWorker._filter_all_link_ids(left) + CapellaPolarionWorker._get_link_id(link): link for link in left } right_id_map = { - CapellaPolarionWorker._get_link_id(link): link - for link in CapellaPolarionWorker._filter_all_link_ids(right) + CapellaPolarionWorker._get_link_id(link): link for link in right } return { lid: left_id_map[lid] @@ -466,28 +464,10 @@ def get_missing_link_ids( def _get_link_id(link: polarion_api.WorkItemLink) -> str: secondary_id = link.secondary_work_item_id if link.secondary_work_item_project: + assert link.secondary_work_item_project is not None secondary_id = f"{link.secondary_work_item_project}/{secondary_id}" return "/".join((link.primary_work_item_id, link.role, secondary_id)) - @staticmethod - def _filter_all_link_ids( - links: cabc.Iterable[polarion_api.WorkItemLink], - ) -> cabc.Iterator[polarion_api.WorkItemLink]: - for link in links: - if link.primary_work_item_id is None: - logger.error( # type: ignore[unreachable] - "Found Work Item Link without source ID: %r", link - ) - continue - - if link.secondary_work_item_id is None: - logger.error( # type: ignore[unreachable] - "Found Work Item Link without target ID: %r", link - ) - continue - - yield link - def compare_and_update_work_items( self, converter_session: data_session.ConverterSession ) -> None: From aa370e84de1dcdc445ba1b3ceb95cbbb09d4c7ac Mon Sep 17 00:00:00 2001 From: micha91 Date: Tue, 27 Aug 2024 15:48:16 +0200 Subject: [PATCH 16/19] build: Update polarion-rest-api-client --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f62fe10b..197b6e30 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -32,7 +32,7 @@ dependencies = [ "capellambse_context_diagrams>=0.3.1,<0.4", "click", "PyYAML", - "polarion-rest-api-client==1.1.1", + "polarion-rest-api-client==1.1.2", "bidict", "cairosvg", "jinja2", From 8dc0ba3596d16d5a5aa38c8bd75881e727a234f7 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Wed, 28 Aug 2024 14:22:34 +0200 Subject: [PATCH 17/19] ci: Fix pre commit hooks --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 17935d0f..e9f0100d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -56,7 +56,7 @@ repos: - capellambse==0.5.69 - click - jinja2 - - polarion-rest-api-client==1.1.1 + - polarion-rest-api-client==1.1.2 - pydantic - types-requests - types-PyYAML From b0cd0d530759261da39c11e41fd974eaed21bcaf Mon Sep 17 00:00:00 2001 From: ewuerger Date: Thu, 29 Aug 2024 11:06:57 +0200 Subject: [PATCH 18/19] fix: Remove debugging logs from dependencies --- capella2polarion/cli.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/capella2polarion/cli.py b/capella2polarion/cli.py index f0c0d1e8..16284455 100644 --- a/capella2polarion/cli.py +++ b/capella2polarion/cli.py @@ -91,6 +91,8 @@ def setup_logger(self) -> None: ) logging.getLogger("httpx").setLevel("WARNING") logging.getLogger("httpcore").setLevel("WARNING") + logging.getLogger("capellambse").setLevel("WARNING") + logging.getLogger("capellambse_context_diagrams").setLevel("WARNING") def load_synchronize_config( self, From dce72af9c1a01cdc03c122d4ac2fdfe3adde5f04 Mon Sep 17 00:00:00 2001 From: ewuerger Date: Fri, 6 Sep 2024 15:17:44 +0200 Subject: [PATCH 19/19] ci: Please Pylint --- .../converters/document_renderer.py | 1 + .../converters/text_work_item_provider.py | 8 +++---- pyproject.toml | 1 + tests/test_documents.py | 6 +---- tests/test_elements.py | 24 ------------------- 5 files changed, 7 insertions(+), 33 deletions(-) diff --git a/capella2polarion/converters/document_renderer.py b/capella2polarion/converters/document_renderer.py index 80610212..5b868b50 100644 --- a/capella2polarion/converters/document_renderer.py +++ b/capella2polarion/converters/document_renderer.py @@ -118,6 +118,7 @@ def __insert_work_item( session.inserted_work_items.append(wi) if self._is_external_document(session): + # pylint: disable-next=line-too-long return polarion_html_helper.POLARION_WORK_ITEM_DOCUMENT_PROJECT.format( pid=wi.id, lid=layout_index, diff --git a/capella2polarion/converters/text_work_item_provider.py b/capella2polarion/converters/text_work_item_provider.py index a75e022a..cbf14934 100644 --- a/capella2polarion/converters/text_work_item_provider.py +++ b/capella2polarion/converters/text_work_item_provider.py @@ -95,19 +95,19 @@ def insert_text_work_items( "paragraph", document.rendering_layouts, self.text_work_item_type ) html_fragments = html_helper.ensure_fragments( - document.home_page_content.value + document.home_page_content.value or "" ) - new_content = [] + new_content: list[html.HtmlElement | str] = [] last_match = -1 for index, element in enumerate(html_fragments): if not isinstance(element, html.HtmlElement): continue if element.tag == "workitem": - new_content += html_fragments[last_match + 1 : index] + new_content.extend(html_fragments[last_match + 1 : index]) last_match = index if work_item := self.new_text_work_items.get( - element.get("id") + element.get("id", "") ): new_content.append( html.fromstring( diff --git a/pyproject.toml b/pyproject.toml index 197b6e30..96c47c01 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -169,6 +169,7 @@ disable = [ "unbalanced-tuple-unpacking", "undefined-variable", "unexpected-keyword-arg", + "unsubscriptable-object", ] enable = [ "c-extension-no-member", diff --git a/tests/test_documents.py b/tests/test_documents.py index 93c4b1cb..a9ddf05a 100644 --- a/tests/test_documents.py +++ b/tests/test_documents.py @@ -546,11 +546,7 @@ def test_render_all_documents_overwrite_headings_layouts( def test_full_authority_document_config(): - with open( - FULL_AUTHORITY_CONFIG, - "r", - encoding="utf-8", - ) as f: + with open(FULL_AUTHORITY_CONFIG, "r", encoding="utf-8") as f: conf = document_config.read_config_file(f) assert len(conf.full_authority) == 2 diff --git a/tests/test_elements.py b/tests/test_elements.py index 60635b2f..cf2305df 100644 --- a/tests/test_elements.py +++ b/tests/test_elements.py @@ -886,14 +886,6 @@ def test_update_work_items_filters_work_items_with_same_checksum( ) ] ) - base_object.mc.converter_session["uuid1"].work_item = ( - data_models.CapellaWorkItem( - id="Obj-1", - uuid_capella="uuid1", - status="open", - type="fakeModelObject", - ) - ) del base_object.mc.converter_session["uuid2"] @@ -919,14 +911,6 @@ def test_update_work_items_same_checksum_force( ) ] ) - base_object.mc.converter_session["uuid1"].work_item = ( - data_models.CapellaWorkItem( - id="Obj-1", - uuid_capella="uuid1", - status="open", - type="fakeModelObject", - ) - ) del base_object.mc.converter_session["uuid2"] @@ -972,14 +956,6 @@ def test_update_links(base_object: BaseObjectContainer): ) ] ) - base_object.mc.converter_session["uuid1"].work_item = ( - data_models.CapellaWorkItem( - id="Obj-1", - uuid_capella="uuid1", - status="open", - type="fakeModelObject", - ) - ) base_object.mc.converter_session["uuid2"].work_item = ( data_models.CapellaWorkItem( id="Obj-2",