Coverage for lobster/tools/trlc/conversion_rule.py: 88%
68 statements
« prev ^ index » next coverage.py v7.10.7, created at 2026-09-22 04:43 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2026-09-22 04:43 +0000
1# LOBSTER - Lightweight Open BMW Software Traceability Evidence Report
2# Copyright (C) 2025-2026 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
3#
4# This program is free software: you can redistribute it and/or modify
5# it under the terms of the GNU Affero General Public License as
6# published by the Free Software Foundation, either version 3 of the
7# License, or (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful, but
10# WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12# Affero General Public License for more details.
13#
14# You should have received a copy of the GNU Affero General Public
15# License along with this program. If not, see
16# <https://www.gnu.org/licenses/>.
19from dataclasses import dataclass
20from typing import Dict, Iterable, List, Optional, Union
22from lobster.tools.trlc.tag_entry import TagEntry
25@dataclass
26class ConversionRule:
27 """Specifies how to convert TRLC Record_Objects to LOBSTER items."""
29 def __init__(
30 self,
31 package: str,
32 record_type: str,
33 namespace: str,
34 version_field: Optional[str] = None,
35 description_fields: Optional[Union[str, Iterable[str]]] = None,
36 justification_up_fields: Optional[Union[str, Iterable[str]]] = None,
37 justification_down_fields: Optional[Union[str, Iterable[str]]] = None,
38 justification_global_fields: Optional[Union[str, Iterable[str]]] = None,
39 tags: Optional[Iterable[Union[str, Dict[str, str]]]] = None,
40 applies_to_derived_types: bool = True,
41 ):
42 self._record_type_name = record_type
43 self._package_name = package
44 self._lobster_namespace = namespace
45 self._version = version_field
46 self._description_fields = self._as_string_list(description_fields)
47 self._justification_up_fields = self._as_string_list(justification_up_fields)
48 self._justification_down_fields = self._as_string_list(
49 justification_down_fields)
50 self._justification_global_fields = self._as_string_list(
51 justification_global_fields)
52 self._tags = self._as_tag_list(tags)
53 self._applies_to_derived_types = applies_to_derived_types
55 def __hash__(self) -> int:
56 return id(self)
58 @property
59 def type_name(self) -> str:
60 return self._record_type_name
62 @property
63 def package_name(self) -> str:
64 return self._package_name
66 @property
67 def applies_to_derived_types(self) -> bool:
68 return self._applies_to_derived_types
70 @property
71 def lobster_namespace(self) -> str:
72 return self._lobster_namespace
74 @property
75 def version(self) -> str:
76 return self._version
78 @staticmethod
79 def _as_string_list(value: Optional[Union[str, Iterable[str]]]) -> List[str]:
80 if value is None:
81 return []
82 if isinstance(value, str): 82 ↛ 83line 82 didn't jump to line 83 because the condition on line 82 was never true
83 return [value]
84 if isinstance(value, list): 84 ↛ 87line 84 didn't jump to line 87 because the condition on line 84 was always true
85 return value
87 raise ValueError(f"Expected str or list, got {type(value)}")
89 @staticmethod
90 def _as_tag_list(
91 tags: Optional[Iterable[Union[str, Dict[str, str]]]],
92 ) -> List[TagEntry]:
93 result = []
94 if tags is not None:
95 for tag in tags:
96 if isinstance(tag, str): 96 ↛ 98line 96 didn't jump to line 98 because the condition on line 96 was always true
97 result.append(TagEntry(field=tag))
98 elif isinstance(tag, dict):
99 result.append(TagEntry(**tag))
100 else:
101 raise ValueError(f"Expected str or dict, got {type(tag)}")
102 return result
104 @property
105 def tags(self) -> List[TagEntry]:
106 return self._tags
108 @property
109 def description_fields(self) -> List[str]:
110 return self._description_fields
112 @property
113 def justification_up_fields(self) -> List[str]:
114 return self._justification_up_fields
116 @property
117 def justification_down_fields(self) -> List[str]:
118 return self._justification_down_fields
120 @property
121 def justification_global_fields(self) -> List[str]:
122 return self._justification_global_fields