Skip to content

Commit

Permalink
merge: Merge pull request #94 from DSD-DBS/check-link-config
Browse files Browse the repository at this point in the history
feat: Detect invalid link configurations
  • Loading branch information
micha91 authored Aug 17, 2024
2 parents 70b3167 + 8f4e7e3 commit 65a312c
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 10 deletions.
72 changes: 64 additions & 8 deletions capella2polarion/converters/converter_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@
from collections import abc as cabc

import yaml
from capellambse.model import common, diagram

logger = logging.getLogger(__name__)

_C2P_DEFAULT = "_C2P_DEFAULT"
DESCRIPTION_REFERENCE_SERIALIZER = "description_reference"
DIAGRAM_ELEMENTS_SERIALIZER = "diagram_elements"


@dataclasses.dataclass
Expand All @@ -33,7 +36,7 @@ class LinkConfig:
lists. They also need be migrated for working references.
"""

capella_attr: str | None = None
capella_attr: str
polarion_role: str | None = None
include: dict[str, str] = dataclasses.field(default_factory=dict)

Expand Down Expand Up @@ -94,6 +97,9 @@ def add_layer(self, layer: str):
"""Add a new layer without configuring any types."""
self._layer_configs[layer] = {}

def _get_global_links(self, c_type: str):
return _filter_links(c_type, self.__global_config.links, True)

def set_layer_config(
self,
c_type: str,
Expand All @@ -113,6 +119,9 @@ def set_layer_config(
)
or self.__global_config
)
# As we set up all types this way, we can expect that all
# non-compliant links are coming from global context here
closest_links = _filter_links(c_type, closest_config.links, True)
p_type = (
type_config.get("polarion_type")
or closest_config.p_type
Expand All @@ -123,8 +132,11 @@ def set_layer_config(
CapellaTypeConfig(
p_type,
type_config.get("serializer") or closest_config.converters,
_force_link_config(type_config.get("links", []))
+ closest_config.links,
_filter_links(
c_type,
_force_link_config(type_config.get("links", [])),
)
+ closest_links,
type_config.get("is_actor", _C2P_DEFAULT),
type_config.get("nature", _C2P_DEFAULT),
)
Expand All @@ -139,21 +151,26 @@ def set_global_config(self, c_type: str, type_config: dict[str, t.Any]):
self._global_configs[c_type] = CapellaTypeConfig(
p_type,
type_config.get("serializer"),
_force_link_config(type_config.get("links", []))
+ self.__global_config.links,
_filter_links(
c_type, _force_link_config(type_config.get("links", []))
)
+ self._get_global_links(c_type),
type_config.get("is_actor", _C2P_DEFAULT),
type_config.get("nature", _C2P_DEFAULT),
)

def set_diagram_config(self, diagram_config: dict[str, t.Any]):
"""Set the diagram config."""
c_type = "diagram"
p_type = diagram_config.get("polarion_type") or "diagram"
self.polarion_types.add(p_type)
links = _force_link_config(diagram_config.get("links", []))
links = _filter_links(
c_type, _force_link_config(diagram_config.get("links", []))
)
self.diagram_config = CapellaTypeConfig(
p_type,
diagram_config.get("serializer") or "diagram",
links + self.__global_config.links,
links + self._get_global_links(c_type),
)

def get_type_config(
Expand Down Expand Up @@ -242,7 +259,7 @@ def _force_link_config(links: t.Any) -> list[LinkConfig]:
config = LinkConfig(capella_attr=link, polarion_role=link)
elif isinstance(link, dict):
config = LinkConfig(
capella_attr=(lid := link.get("capella_attr")),
capella_attr=(lid := link["capella_attr"]),
polarion_role=link.get("polarion_role", lid),
include=link.get("include", {}),
)
Expand All @@ -254,3 +271,42 @@ def _force_link_config(links: t.Any) -> list[LinkConfig]:
continue
result.append(config)
return result


def _filter_links(
c_type: str, links: list[LinkConfig], is_global: bool = False
):
if c_type == "diagram":
c_class = diagram.Diagram
else:
if not (c_classes := common.find_wrapper(c_type)):
logger.error("Did not find any matching Wrapper for %s", c_type)
return links
c_class = c_classes[0]

available_links = []
for link in links:
cappela_attr = link.capella_attr.split(".")[0]
if (
cappela_attr == DESCRIPTION_REFERENCE_SERIALIZER
or (
cappela_attr == DIAGRAM_ELEMENTS_SERIALIZER
and c_class == diagram.Diagram
)
or hasattr(c_class, cappela_attr)
):
available_links.append(link)
else:
if is_global:
logger.info(
"Global link %s is not available on Capella type %s",
cappela_attr,
c_type,
)
else:
logger.error(
"Link %s is not available on Capella type %s",
cappela_attr,
c_type,
)
return available_links
4 changes: 2 additions & 2 deletions capella2polarion/converters/link_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ def __init__(
self.role_prefix = role_prefix

self.serializers: dict[str, _Serializer] = {
"description_reference": self._handle_description_reference_links,
"diagram_elements": self._handle_diagram_reference_links,
converter_config.DESCRIPTION_REFERENCE_SERIALIZER: self._handle_description_reference_links, # pylint: disable=line-too-long
converter_config.DIAGRAM_ELEMENTS_SERIALIZER: self._handle_diagram_reference_links, # pylint: disable=line-too-long
"input_exchanges": self._handle_exchanges,
"output_exchanges": self._handle_exchanges,
}
Expand Down
24 changes: 24 additions & 0 deletions tests/test_elements.py
Original file line number Diff line number Diff line change
Expand Up @@ -1750,3 +1750,27 @@ def test_read_config_with_custom_params(model: capellambse.MelodyModel):
serializer.serialize_all()
assert wrapped_render.call_count == 1
assert wrapped_render.call_args_list[0][1] == {"depth": 1}

@staticmethod
def test_read_config_links(caplog: pytest.LogCaptureFixture):
caplog.set_level("DEBUG")
config = converter_config.ConverterConfig()
with open(TEST_MODEL_ELEMENTS_CONFIG, "r", encoding="utf8") as f:
config.read_config_file(f)

assert config.diagram_config
assert not any(
link
for link in config.diagram_config.links
if link.capella_attr == "parent"
)
assert caplog.record_tuples[0][1] == 20
assert (
caplog.record_tuples[0][2]
== "Global link parent is not available on Capella type diagram"
)
assert caplog.record_tuples[1][1] == 40
assert (
caplog.record_tuples[1][2]
== "Link exchanged_items is not available on Capella type FunctionalExchange"
)

0 comments on commit 65a312c

Please sign in to comment.