Skip to content

Commit

Permalink
feat: first version of a ConverterDataSession and added nature and is…
Browse files Browse the repository at this point in the history
…_actor to the converter config
  • Loading branch information
micha91 committed Jan 9, 2024
1 parent f52d8cf commit 7e6ee2c
Show file tree
Hide file tree
Showing 3 changed files with 156 additions and 51 deletions.
165 changes: 114 additions & 51 deletions capella2polarion/converters/converter_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,79 +16,142 @@ class CapellaTypeConfig:
p_type: str | None = None
converter: str | None = None
links: list[str] = dataclasses.field(default_factory=list)
actor: bool | None = None
nature: bool | None = None


def _default_type_conversion(c_type: str) -> str:
return c_type[0].lower() + c_type[1:]


class ConverterConfig:
"""The overall Config for capella2polarion."""

def __init__(self, synchronize_config: typing.TextIO):
config_dict = yaml.safe_load(synchronize_config)
self._layer_configs: dict[str, dict[str, CapellaTypeConfig]] = {}
self._layer_configs: dict[str, dict[str, list[CapellaTypeConfig]]] = {}
self._global_configs: dict[str, CapellaTypeConfig] = {}
# We handle the cross layer config separately as global_configs
global_config_dict = config_dict.pop("*", {})
all_type_config = global_config_dict.pop("*", {})
global_links = all_type_config.get("links", [])
self.__global_config = CapellaTypeConfig(links=global_links)

def _read_capella_type_configs(conf: dict | list | None) -> list[dict]:
if conf is None:
return [{}]
if isinstance(conf, dict):
return [conf]

# We want to have the most generic config first followed by those
# having actor set to None
return sorted(
conf,
key=lambda c: int(c.get("actor") is not None)
+ 2 * int(c.get("nature") is not None),
)

for c_type, type_config in global_config_dict.items():
type_config = type_config or {}
self._global_configs[c_type] = CapellaTypeConfig(
type_config.get("polarion_type"),
type_config.get("polarion_type")
or _default_type_conversion(c_type),
type_config.get("serializer"),
type_config.get("links", []) + global_links,
type_config.get("actor"),
type_config.get("nature"),
)

for layer, type_configs in config_dict.items():
self._layer_configs[layer] = {}
for c_type, type_config in type_configs.items():
self._layer_configs[layer][c_type] = CapellaTypeConfig(
type_config.get("polarion_type")
or self._global_configs.get(
c_type, self.__global_config
).p_type,
type_config.get("serializer")
or self._global_configs.get(
c_type, self.__global_config
).converter,
type_config.get("links", [])
+ self._global_configs.get(
c_type, self.__global_config
).links,
)

def _default_type_conversion(self, c_type: str) -> str:
return c_type[0].lower() + c_type[1:]

def _get_type_configs(
self, layer: str, c_type: str
for c_type, c_type_config in type_configs.items():
type_configs = _read_capella_type_configs(c_type_config)
self._layer_configs[layer][c_type] = []
for type_config in type_configs:
closest_config = (
self.get_type_config(
layer,
c_type,
type_config.get("actor"),
type_config.get("nature"),
)
or self.__global_config
)
self._layer_configs[layer][c_type].append(
CapellaTypeConfig(
type_config.get("polarion_type")
or closest_config.p_type
or _default_type_conversion(c_type),
type_config.get("serializer")
or closest_config.converter,
type_config.get("links", [])
+ closest_config.links,
type_config.get("actor"),
type_config.get("nature"),
)
)

def get_type_config(
self,
layer: str,
c_type: str,
actor: bool | None = None,
nature: str | None = None,
) -> CapellaTypeConfig | None:
return self._layer_configs.get(layer, {}).get(
c_type
) or self._global_configs.get(c_type)

def get_polarion_type(self, layer: str, c_type: str) -> str:
"""Return polarion type for a given layer and Capella type."""
type_config = (
self._get_type_configs(layer, c_type) or self.__global_config
)
return type_config.p_type or self._default_type_conversion(c_type)

def get_serializer(self, layer: str, c_type: str) -> str | None:
"""Return the serializer name for a given layer and Capella type."""
type_config = (
self._get_type_configs(layer, c_type) or self.__global_config
)
return type_config.converter

def get_links(self, layer: str, c_type: str) -> list[str]:
"""Return the list of link types for a given layer and Capella type."""
type_config = (
self._get_type_configs(layer, c_type) or self.__global_config
)
return type_config.links

def __contains__(self, item: tuple[str, str]):
"""Get the type config for a given layer and capella_type."""
layer_configs = self._layer_configs.get(layer, {}).get(c_type)
global_config = self._global_configs.get(c_type)
if layer_configs:
if config := next(
filter(
lambda c: c is not None
and c.actor == actor
and c.nature == nature,
layer_configs,
),
None,
):
return config

if config := next(
filter(
lambda c: c is not None
and c.actor == actor
and c.nature is None,
layer_configs,
),
None,
):
return config

if config := next(
filter(
lambda c: c is not None
and c.actor is None
and c.nature == nature,
layer_configs,
),
None,
):
return config

if config := next(
filter(
lambda c: c is not None
and c.actor is None
and c.nature is None,
layer_configs,
),
None,
):
return config

return global_config

def __contains__(
self,
item: tuple[str, str, typing.Optional[bool], typing.Optional[str]],
):
"""Check if there is a config for a given layer and Capella type."""
layer, c_type = item
return self._get_type_configs(layer, c_type) is not None
layer, c_type, actor, nature = item
return self.get_type_config(layer, c_type, actor, nature) is not None
25 changes: 25 additions & 0 deletions capella2polarion/converters/converter_data_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Copyright DB InfraGO AG and contributors
# SPDX-License-Identifier: Apache-2.0
"""A module to store data during the conversion process."""
from __future__ import annotations

import dataclasses

from capellambse.model import GenericElement

from capella2polarion import data_models as dm
from capella2polarion.converters import converter_config


@dataclasses.dataclass
class ConverterData:
"""Data class holding all information needed during Conversion."""

layer: str
type_config: converter_config.CapellaTypeConfig
capella_element: GenericElement | None = None
work_item: dm.CapellaWorkItem | None = None
description_references: list[str] = dataclasses.field(default_factory=list)


ConverterSession: dict[str, ConverterData]
17 changes: 17 additions & 0 deletions tests/data/model_elements/new_config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,20 @@ oa: # Specify below
- exchange_items
OperationalCapability:
serializer: include_pre_and_post_condition
pa:
PhysicalComponent:
- actor: false
nature: null
polarion_type: PhysicalComponent
- actor: false
nature: NODE
polarion_type: PhysicalComponentNode
- actor: false
nature: BEHAVIOR
polarion_type: PhysicalComponentBehavior
- actor: true
nature: NODE
polarion_type: PhysicalActorNode
- actor: true
nature: BEHAVIOR
polarion_type: PhysicalActorBehavior

0 comments on commit 7e6ee2c

Please sign in to comment.