Path:
strictdoc/backend/sdoc/models/document_config.py
Lines:
234
Non-empty lines:
204
Non-empty lines covered with requirements:
204 / 204 (100.0%)
Functions:
17
Functions covered by requirements:
17 / 17 (100.0%)
- "1.6. Document metadata" (REQUIREMENT)
- "1.7. Document configuration" (REQUIREMENT)
1
"""2
@relation(SDOC-SRS-110, SDOC-SRS-151, scope=file)3
"""4
5
from typing import TYPE_CHECKING, Any, List, Optional, Tuple
6
7
from strictdoc.backend.sdoc.constants import SDocMarkup
8
from strictdoc.backend.sdoc.models.inline_link import InlineLink
9
from strictdoc.helpers.auto_described import auto_described
10
11
if TYPE_CHECKING:
12
from strictdoc.backend.sdoc.models.document import SDocDocument
13
14
15
@auto_described16
class DocumentCustomMetadataKeyValuePair:
17
def __init__(
18
self,
19
*,
20
parent: Optional["DocumentCustomMetadata"] = None,
21
key: Optional[str],
22
parts: List[Any],
23
) -> None:
24
self.parent: Optional[DocumentCustomMetadata] = parent
25
self.key = key
26
self.parts: List[Any] = parts
27
for part in parts:
28
if isinstance(part, InlineLink):
29
part.parent = self
30
31
def get_text_value(self) -> str:
32
text = ""
33
for part in self.parts:
34
if isinstance(part, str):
35
text += part
36
elif isinstance(part, InlineLink):
37
text += "[LINK: "
38
text += part.link
39
text += "]"
40
else:
41
raise NotImplementedError(part) # pragma: no cover
42
return text
43
44
def get_owning_node(self) -> "SDocDocument":
45
assert self.parent is not None
46
assert self.parent.parent is not None
47
document = self.parent.parent.parent
48
assert document is not None
49
return document
50
51
52
@auto_described53
class DocumentCustomMetadata:
54
def __init__(
55
self,
56
*,
57
parent: Optional["DocumentConfig"] = None,
58
entries: List[DocumentCustomMetadataKeyValuePair],
59
) -> None:
60
self.parent: Optional[DocumentConfig] = parent
61
self.entries: List[DocumentCustomMetadataKeyValuePair] = entries
62
63
64
@auto_described65
class DocumentConfig:
66
@staticmethod67
def default_config(document: Optional["SDocDocument"]) -> "DocumentConfig":
68
return DocumentConfig(
69
parent=document,
70
version=None,
71
date=None,
72
uid=None,
73
classification=None,
74
requirement_prefix=None,
75
root=None,
76
enable_mid=None,
77
relation_field=None,
78
markup=None,
79
auto_levels=None,
80
layout=None,
81
requirement_style=None,
82
requirement_in_toc=None,
83
default_view=None,
84
custom_metadata=None,
85
)86
87
def __init__(
88
self,
89
*,
90
parent: Optional["SDocDocument"],
91
version: Optional[str],
92
date: Optional[str],
93
uid: Optional[str],
94
classification: Optional[str],
95
requirement_prefix: Optional[str],
96
root: Optional[str],
97
enable_mid: Optional[str],
98
relation_field: Optional[str],
99
markup: Optional[str],
100
auto_levels: Optional[str],
101
layout: Optional[str],
102
requirement_style: Optional[str],
103
requirement_in_toc: Optional[str],
104
default_view: Optional[str],
105
custom_metadata: Optional[DocumentCustomMetadata],
106
view_style_tag: Optional[str] = None,
107
node_in_toc_tag: Optional[str] = None,
108
) -> None:
109
self.parent = parent
110
self.version: Optional[str] = version
111
self.date: Optional[str] = date
112
113
meaningful_uid: Optional[str] = None
114
if uid is not None and len(uid) > 0:
115
meaningful_uid = uid
116
self.uid: Optional[str] = meaningful_uid
117
118
self.classification: Optional[str] = classification
119
self.requirement_prefix: Optional[str] = requirement_prefix
120
121
self.root: Optional[bool] = (
122
True if root == "True" else (False if root == "False" else None)
123
)124
self.enable_mid: Optional[bool] = (
125
True126
if enable_mid == "True"
127
else (False if root == "False" else None)
128
)129
self.relation_field: Optional[str] = (
130
relation_field131
if relation_field is not None and len(relation_field) > 0
132
else None
133
)134
135
self.markup: Optional[str] = markup
136
self.auto_levels: bool = auto_levels is None or auto_levels == "On"
137
138
if layout is not None:
139
if len(layout) > 0:
140
assert layout in ("Default", "Website")
141
else:
142
layout = None
143
self.layout: Optional[str] = layout
144
145
# Possible requirement styles:146
# Simple, Table, Rows.147
self.requirement_style: Optional[str] = requirement_style
148
self.view_style_tag: Optional[str] = view_style_tag
149
150
self.requirement_in_toc: Optional[str] = requirement_in_toc
151
self.node_in_toc_tag: Optional[str] = node_in_toc_tag
152
153
self.default_view: Optional[str] = default_view
154
self.ng_auto_levels_specified = auto_levels is not None
155
156
self.ng_line_start: int = 0
157
self.ng_col_start: int = 0
158
159
self.custom_metadata: Optional[DocumentCustomMetadata] = custom_metadata
160
161
def get_markup(self) -> str:
162
if self.markup is None:
163
return SDocMarkup.RST
164
return self.markup
165
166
def get_requirement_style_mode(self) -> str:
167
if (
168
self.requirement_style is None
169
or self.requirement_style == "Narrative"
170
):171
return "narrative"
172
if self.requirement_style == "Plain":
173
return "plain"
174
if self.requirement_style in (
175
"Inline",
176
"Simple",
177
):178
return "simple"
179
if self.requirement_style == "Table":
180
return "table"
181
if self.requirement_style == "Zebra":
182
return "zebra"
183
raise NotImplementedError(self.requirement_style)
184
185
def is_requirement_in_toc(self) -> bool:
186
return (
187
self.requirement_in_toc is None or self.requirement_in_toc == "True"
188
)189
190
def get_prefix(self) -> str:
191
if self.requirement_prefix is not None:
192
return self.requirement_prefix
193
return "REQ-"
194
195
def get_relation_field(self) -> str:
196
return self.relation_field or "UID"
197
198
def has_meta(self) -> bool:
199
# TODO: When OPTIONS are not provided to a document, the self.number and200
# self.version are both None. Otherwise, they become empty strings "".201
# This issue might deserve a bug report to TextX.202
return (
203
(self.uid is not None and len(self.uid) > 0)
204
or (self.version is not None and len(self.version) > 0)
205
or (
206
self.classification is not None and len(self.classification) > 0
207
)208
)209
210
def has_custom_metadata(self) -> bool:
211
return len(self.get_custom_metadata()) > 0
212
213
def get_custom_metadata(self) -> List[Tuple[str, str]]:
214
if (
215
self.custom_metadata is not None
216
and self.custom_metadata.entries is not None
217
):218
reserved_keys = {
219
key220
for key, value in (
221
("UID", self.uid),
222
("VERSION", self.version),
223
("DATE", self.date),
224
("CLASSIFICATION", self.classification),
225
)226
if value is not None and len(value) > 0
227
}228
return [
229
(entry.key, entry.get_text_value())
230
for entry in self.custom_metadata.entries
231
if entry.key is not None
232
and entry.key.upper() not in reserved_keys
233
]234
return []